﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Reflection;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections;
using System.IO;
using System.Xml;
using System.Threading;
/*
 * Project Home : http://code.google.com/p/klsudoku
 * Project Owner: ttylikl@gmail.com Email:ttylikl@qq.com
 * Project Blog : http://www.cnblogs.com/ttylikl
 * All Files of this project is free to use , but you should keep the information above when you copy&use it.
 * Infomation Modify Date: 2009.02.22
 * 
 * */

namespace SudokuPanel
{
    public partial class SudokuPanel : Form
    {
        ConfigInfo ci = ConfigInfo.Instance();
        public MyButton mybutton;
        public cellset[] m_cellsets;
        public puzzle m_puzzle;
        private solver m_solver;
        private puzzle m_puzzle2;

        private int tip_count;
        private int undo_count;
        private int undo_step_count;

        private pubfun.PuzzleStringFormat _formatType;//控制复制或导出题目的缺省格式
        public pubfun.PuzzleStringFormat formatType
        {
            get { return _formatType; }
            set { 
                _formatType=value;
                switch (value)
                {
                    case pubfun.PuzzleStringFormat.FormatMatrix9x9: ci["PuzzleStringFormat"] = "2"; break;
                    case pubfun.PuzzleStringFormat.FormatTableAscii: ci["PuzzleStringFormat"] = "3"; break;
                    case pubfun.PuzzleStringFormat.FormatLine91:
                    default: ci["PuzzleStringFormat"] = "1"; break;
                }
            }
        }
        private List<List<operation>> m_ops=new List<List<operation>>();
        private int m_current_op = 0;

        private DateTime dtstart=DateTime.Now;
        private int dtsecs = 0;

        public List<Label> x_lable;
        public List<Label> y_lable;

        public enum State { PLAYING,SHOWHINT,INPUTING };
        private State sta = State.PLAYING;
        private operation hint_op = null; //保留提示的操作内容
        private List<int[]> hints = null;//保留提示设置

        public bool bShowTagCandidate;

        public Color SolidNumberForeColor = Color.Black;
        public Color NumberForeColor = Color.Blue;
        public Color HotNumberForeColor = Color.Black ; //Color.Magenta;
        public Color HotSpotColor = Color.Tomato;
        public Color HotNumberBackColor = Color.SkyBlue;
        public void loadColorConfig()
        {
            SolidNumberForeColor = Color.FromName(ci["SolidNumberForeColor","Black"]);
            ci["SolidNumberForeColor"] = SolidNumberForeColor.ToKnownColor().ToString();
            NumberForeColor = Color.FromName(ci["NumberForeColor", "Blue"]);
            ci["NumberForeColor"] = NumberForeColor.ToKnownColor().ToString();

            HotNumberForeColor = Color.FromName(ci["HotNumberForeColor", "Black"]);
            ci["HotNumberForeColor"] = HotNumberForeColor.ToKnownColor().ToString();
            HotNumberBackColor = Color.FromName(ci["HotNumberBackColor", "SkyBlue"]);
            ci["HotNumberBackColor"] = HotNumberBackColor.ToKnownColor().ToString();
            
            HotSpotColor = Color.FromName(ci["HotSpotColor", "Tomato"]);
            ci["HotSpotColor"] = HotSpotColor.ToKnownColor().ToString();
            
        }
        private int _hotnum = 0;//不显示候选数时默认操作数
        public int hotnum
        {
            get { return _hotnum; }
            set
            {
                if (value != _hotnum)
                {
                    if (_hotnum != 0)
                    {
                        y_lable[_hotnum - 1].BackColor = DefaultBackColor;
                        y_lable[_hotnum - 1].ForeColor = Color.DarkGray;
                        tagHotNumber(_hotnum, false);
                    }
                    if(value>0)
                    {
                        y_lable[value - 1].BackColor = Color.DarkGray;
                        y_lable[value - 1].ForeColor = Color.Black;
                        tagHotNumber(value, true);
                    }

                    _hotnum = value;
                }

                ci.notifyWorking(false);

                update_y_label();
                hotpoint=hotpoint;//避免切换热点数后，热点数格消失的问题
            }
        }
        //1.2 2009.5.7
        public Color getForeColor(cell c)
        {
            return getForeColor(c, hotnum);
        }
        public Color getForeColor(cell c, int hn)
        {
            if(c.solid)
                return SolidNumberForeColor;
            
            //if (c.Text == hn.ToString() && pubfun.str2int(ci["show_hot_number", "1"]) > 0)
            //{
            //    return HotNumberForeColor;
            //}
            if(c.Text!="")
            {
                return NumberForeColor;
            }
            return SolidNumberForeColor;
        }

        public Color getBackColor(cell c)
        {
            return getBackColor(c, hotnum);
        }
        public Color getBackColor(cell c,int hn)
        {
            if (c.Text == hn.ToString() && pubfun.str2int(ci["show_hot_number", "1"]) > 0)
                return Color.SkyBlue;

            return c.bkcolor;
        }
        public Color getBackColor(subcell sc)
        {
            return getBackColor(sc, hotnum);
        }
        public Color getBackColor(subcell sc,int hn)
        {
            if (hn == 0)
                return sc.bkcolor;
            //if (sc.ForeColor == sc.bkcolor)
            if (m_puzzle[sc.xy, hn] == pubfun.Flag.tag)
                return sc.bkcolor;//解决右键消除了候选数的情况
            if (sc.Text == hn.ToString() && pubfun.str2int(ci["show_hot_number", "1"]) > 0)
                return Color.SkyBlue;

            return sc.bkcolor;
        }
        void tagHotNumber(cell c,int value,bool ishot)
        {
            bool hotoff=(pubfun.str2int(ci["show_hot_number","1"]) == 0);
            //if (c.Visible)
            {
                if (c.Text == "")
                {
                    subcell sc = c.m_subcells[value - 1];
                    if (sc.Visible)
                    {
                        if(m_puzzle[sc.xy,value]== pubfun.Flag.tag)
                        {
                            sc.BackColor = sc.bkcolor;
                            return;
                        }
                        sc.ForeColor = (ishot && !hotoff) ? HotNumberForeColor : SolidNumberForeColor;
                        if (ishot && !hotoff)
                        {
                            sc.BackColor = getBackColor(sc, value);
                        }
                        else
                        {
                            sc.BackColor = sc.bkcolor;
                        }
                    }
                }
                else 
                {
                    c.ForeColor = getForeColor(c, value);
                    if (ishot && !hotoff)
                    {
                        Color bc = getBackColor(c, value);
                        c.BackColor = bc;
                    }
                    else
                        c.BackColor = c.bkcolor;
                }
            }
        }
        void tagHotNumber(int value, bool ishot)
        {
            String strValue = value.ToString();
            foreach (cellset cs in m_cellsets)
            {
                foreach (cell c in cs.m_cells)
                {
                    tagHotNumber(c, value, ishot);
                }
            }
        }
     
        
        private bool _bShowCandidates;
        public bool bShowCandidates{
            get { return _bShowCandidates; }
            set {
                if (value != _bShowCandidates)
                {
                    _bShowCandidates = value;
                    m_puzzle.validate_set = value;//改变puzzle是否校验设置数字的选项
                    this.toolStripButtonShowCandidates.Checked = value;
                    show_all_candidates(value);
                    updatePanel();
                }
            }
        }
        public void show_all_candidates(bool show)
        {
            for (int y = 1; y <= 9; ++y)
            {
                for (int x = 1; x <= 9; ++x)
                {
                    Point p = new Point(x, y);
                    cell c = getCell(p);
                    for (int j = 0; j < 9; ++j)
                    {
                        pubfun.Flag num = m_puzzle[p, j+1];
                        if (num == pubfun.Flag.none )
                            c.m_subcells[j].Visible = false;
                        else if (num == pubfun.Flag.normal)
                        {
                            c.m_subcells[j].Visible = show;
                            c.m_subcells[j].ForeColor = Color.Black;
                            c.m_subcells[j].BackColor = getBackColor(c.m_subcells[j]);
                        }
                        else if (num == pubfun.Flag.tag)
                        {
                            c.m_subcells[j].Visible = show;
                            //根据配置显示被排除的候选数
                            if (bShowTagCandidate)
                                c.m_subcells[j].ForeColor = Color.Gainsboro;
                            else
                                c.m_subcells[j].ForeColor = c.m_subcells[j].bkcolor;
                            //c.m_subcells[j].ForeColor = Color.DarkGray;
                            c.m_subcells[j].BackColor = getBackColor(c.m_subcells[j]);
                        }

                    }
                }
            }
        }
        private Point _hotpoint = new Point(1, 1);
        //热点位置，变更时相应设置颜色
        public Point hotpoint
        {
            get { return _hotpoint; }
            set {
                if (value == _hotpoint)
                {
                    //判断颜色是否被清除了
                    cell oc = getCell(_hotpoint);
                    oc.BackColor =(ci.bShowHotspot)?HotSpotColor:getBackColor(oc);
                    return;
                }
                //如果显示了tab pop，则应该判断是否鼠标还在tabpop上
                if (tabPop.Visible) return;

                cell c = getCell(_hotpoint);
                c.BackColor = (this.sta == State.SHOWHINT) ? c.ml_bkcolor : getBackColor(c);// c.bkcolor;
                foreach (subcell sc in c.m_subcells)
                {
                    sc.BackColor = (this.sta == State.SHOWHINT) ? sc.ml_bkcolor : getBackColor(sc);// sc.bkcolor;
                }
                if (pubfun.isValidPoint(value))
                {
                    tabPop.Visible = false;
                    _hotpoint = value; 
                    c = getCell(_hotpoint);
                    c.ml_bkcolor = c.BackColor;
                    foreach (subcell sc in c.m_subcells)
                    {
                        sc.ml_bkcolor = sc.BackColor;
                    }
                    c.BackColor = (ci.bShowHotspot) ? HotSpotColor : getBackColor(c);
                }

                ci.notifyWorking(false);
            }
        }

        //目前未启用下面几个变量控制
        //bAutoSet 是否自动点击即设置数字（true则lcick设置数字，ctrl+lcick设置候选数，false则相反）
        //bAutoCand 是否在设置多个数字时自动切换为候选数
        public bool bAutoSet = true;
        public bool bAutoCand = true;

        public void doTest()
        {
        }

        public SudokuPanel()
        {
            InitializeComponent();


            //预先载入配置项
            //ConfigInfo ci=ConfigInfo.Instance();
            this.LocationChanged += new EventHandler(SudokuPanel_LocationChanged);
            if(pubfun.str2int(ci["run_count"]) == 1)
            {
                MessageBox.Show("欢迎使用KLSudoku进行游戏！\nKLSudoku完全免费开源，如有任何建议和意见，欢迎给ttylikl@qq.com写邮件！\n强烈建议从KLSudoku菜单里下载最新的帮助手册，了解KLSudoku的操作指南和学习大量的数独解题技巧！\n同时欢迎访问KLSudoku相关博客和帮助网页（见帮助菜单），并加入数独爱好者的QQ群 106249 ！", "欢迎使用KLSudoku！");
            }
            mybutton = new MyButton();
            this.Controls.Add(mybutton);
            mybutton.Focus();

            this.ToolStripMenuItemLvl = new ToolStripMenuItem[ConfigInfo.lvlList.Length];
            for (int i = 0; i < ConfigInfo.lvlList.Length;++i )
            {
                ToolStripMenuItemLvl[i]=new ToolStripMenuItem();
                ToolStripMenuItemLvl[i].Name = "ToolStripMenuItemLvl_"+i;
                ToolStripMenuItemLvl[i].Size = new System.Drawing.Size(152, 22);
                ToolStripMenuItemLvl[i].Text = ConfigInfo.lvlList[i];
            }
            // 
            // buttonGerator
            // 
            this.generatorMenu.DropDownItems.AddRange(ToolStripMenuItemLvl);
            this.generatorMenu.ImageTransparentColor = System.Drawing.Color.Transparent;

            this.SuspendLayout();


            Point p = new Point(60, 90);
            SudokuPanel panel = this;

            //布置面板数格
            m_cellsets = new cellset[9];
            Point pp = new Point(p.X + 1, p.Y + 1);
            for (int i = 0; i < 9; ++i)
            {
                m_cellsets[i] = new cellset(panel, pp, i + 1);
                pp = new Point(p.X + 1 + ((i + 1) % 3) * m_cellsets[i].Width, p.Y + 1 + ((i + 1) / 3) * m_cellsets[i].Height);
            }

            //布置坐标标签
            x_lable = new List<Label>();
            y_lable = new List<Label>();
            for (int i = 0; i < 9; ++i)
            {
                Label lb = new Label();
                y_lable.Add(lb);
                lb.Click += new EventHandler(lb_Click);
                lb.Text = (i + 1).ToString();
                lb.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
                lb.Font = new System.Drawing.Font("黑体", 24F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                lb.ForeColor = Color.DarkGray;
                Point lp=new Point(i+1,1);
                cell c=getCell(lp);
                lp=c.Location;
                lp.Y-=c.Height;
                lb.Location = lp;
                lb.Name = lb.Text;
                lb.Size = c.Size;
                lb.TabIndex = i+1;
                this.Controls.Add(lb);
                lb.MouseEnter += new EventHandler(lb_MouseEnter);
                lb.MouseLeave += new EventHandler(lb_MouseLeave);
            }
            char ch = 'A';
            --ch;
            for (int i = 0; i < 9; ++i)
            {
                Label lb = new Label();
                x_lable.Add(lb);
                ++ch;
                lb.Text = ch.ToString();
                lb.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
                lb.Font = new System.Drawing.Font("黑体", 24F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                lb.ForeColor = Color.DarkGray;
                Point lp = new Point(1,i + 1);
                cell c = getCell(lp);
                lp = c.Location;
                lp.X -= c.Width;
                lb.Location = lp;
                lb.Name = lb.Text;
                lb.Size = c.Size;
                lb.TabIndex = i + 1;
                this.Controls.Add(lb);
            }

            this.Size = new Size(m_cellsets[0].Width * 3 + 30 + p.X, m_cellsets[0].Height * 3 + 60 + p.Y);

            m_puzzle = new puzzle();
            m_solver = new solver(m_puzzle);
            m_puzzle2 = new puzzle();

            for(int y=1;y<=9;++y)
            {
                for(int x=1;x<=9;++x)
                {
                    p=new Point(x,y);
                    cell c = getCell(p);
                    c.xy = p;
                }
            }

            init_tab_pop();

            loadConfig();


            String strX = ci["last_localtion_x"];
            String strY = ci["last_localtion_y"];
            String strW = ci["last_size_width"];
            String strH = ci["last_size_height"];
            bool bMaxWindow = true;
            int lx = 0;
            int ly = 0;
            int lw = 0;
            int lh = 0;
            if (ci["last_window_maximized"] != "1")
            {
                if (strX != "" && strY != "" && strW != "" && strH != "")
                {
                    lx = pubfun.str2int(strX);
                    ly = pubfun.str2int(strY);
                    lw = pubfun.str2int(strW);
                    lh = pubfun.str2int(strH);
                    this.Location = new Point(lx, ly);
                    this.Size = new Size(lw, lh);
                    bMaxWindow = false;
                }
            }

            if (bMaxWindow || ci["last_window_maximized"] == "1")
                this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
            this.ResumeLayout();

            startNewPuzzle();

            timer1.Start();
            timer2.Start();

            //部分事件使用到需要在上面初始化的变量，所以先初始化变量再设置事件处理器
            this.SizeChanged += new System.EventHandler(this.SudokuPanel_SizeChanged);
            this.Size = new System.Drawing.Size(this.Size.Width + 1, this.Size.Height+1);//强迫产生一次SizeChanged事件，避免在Win7系统上的问题

            this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SudokuPanel_FormClosed);
            this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.doKeyUp);
            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.doKeyDown);

        }

        void SudokuPanel_LocationChanged(object sender, EventArgs e)
        {
            
        }

        int tabshow = 0;
        void show_tab_pop(bool show)
        {
            cell c = getCell(hotpoint);
            tabPop.Left = c.Location.X;
            tabPop.Top = c.Location.Y;
            cell rbc = getCell(new Point(9, 9));
            if (tabPop.Bottom > rbc.Bottom)
                tabPop.Top -= tabPop.Bottom - rbc.Bottom;
            if (tabPop.Right > rbc.Right)
                tabPop.Left -= tabPop.Right - rbc.Right;

            if(show) 
                tabPop.Visible = true;
            if (tabshow == 0)
                tabPop.SelectTab(tabSetCandidate.Name);
            else
                tabPop.SelectTab(tabSetNumber.Name);
        }
        void init_tab_pop()
        {
            tabPop.Visible = false;
            //tabPop.MouseEnter+=new EventHandler(tabPop_MouseEnter);
            //tabPop.MouseLeave+=new EventHandler(tabPop_MouseLeave);
            tabSetCandidate.MouseLeave += new EventHandler(tabPop_MouseLeave);
            tabSetNumber.MouseLeave += new EventHandler(tabPop_MouseLeave);
            for (int tab = 0; tab < 2; ++tab)
            {
                for (int i = 0; i < 9; ++i)
                {
                    Label lb = new Label();
                    lb.AutoSize = true;
                    lb.Location = new System.Drawing.Point(6 + (i % 3) * 17, 3 + (i / 3) * 23);
                    lb.Name = "label" + i;
                    lb.Size = new System.Drawing.Size(11, 12);
                    lb.TabIndex = i + 1;
                    lb.Text = (i + 1).ToString();
                    lb.Font = new System.Drawing.Font("黑体", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                    lb.MouseEnter += new System.EventHandler(label_MouseEnter);
                    lb.MouseLeave += new System.EventHandler(label_MouseLeave);
                    if (tab == 0)
                    {
                        lb.MouseClick += new System.Windows.Forms.MouseEventHandler(this.label1_Click);
                        this.tabSetCandidate.Controls.Add(lb);
                    }
                    else
                    {
                        this.tabSetNumber.Controls.Add(lb);
                        lb.MouseClick += new System.Windows.Forms.MouseEventHandler(this.label2_Click);
                    }
                }
                //Label lbcancel = new Label();
                //lbcancel.AutoSize = true;
                //lbcancel.Location = new System.Drawing.Point(57, 26);
                //lbcancel.Name = "labelcancel";
                //lbcancel.Size = new System.Drawing.Size(29, 12);
                //lbcancel.TabIndex = 11;
                //lbcancel.Text = "取消";
                //lbcancel.Font = new System.Drawing.Font("黑体", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                //lbcancel.MouseEnter += new System.EventHandler(label_MouseEnter);
                //lbcancel.MouseLeave += new System.EventHandler(label_MouseLeave);

                Label lb0 = new Label();
                lb0.AutoSize = true;
                lb0.Location = new System.Drawing.Point(57, 3);
                lb0.Name = "label0";
                lb0.Size = new System.Drawing.Size(11, 12);
                lb0.TabIndex = 10;
                lb0.Text = "0";
                lb0.Font = new System.Drawing.Font("黑体", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                lb0.MouseEnter += new System.EventHandler(label_MouseEnter);
                lb0.MouseLeave += new System.EventHandler(label_MouseLeave);

                if (tab == 0)
                {
                    //lbcancel.MouseClick += new System.Windows.Forms.MouseEventHandler(this.label1_Click);
                    //this.tabSetCandidate.Controls.Add(lbcancel);
                    lb0.MouseClick += new System.Windows.Forms.MouseEventHandler(this.label1_Click);
                    this.tabSetCandidate.Controls.Add(lb0);
                }
                else
                {
                    //lbcancel.MouseClick += new System.Windows.Forms.MouseEventHandler(this.label2_Click);
                    //this.tabSetNumber.Controls.Add(lbcancel);
                    lb0.MouseClick += new System.Windows.Forms.MouseEventHandler(this.label2_Click);
                    this.tabSetNumber.Controls.Add(lb0);
                }
            }
        }

        void tabPop_MouseEnter(object sender, EventArgs e)
        {
            Debug.WriteLine("Enter");
        }

        void tabPop_MouseLeave(object sender, EventArgs e)
        {
            //tabPop.Visible = false;
            Debug.WriteLine("Leave");
        }

        Label old_y_label = null;
        Color old_y_label_color = DefaultBackColor;
        void lb_MouseEnter(object sender, EventArgs e)
        {
            cell c = getCell(hotpoint);//取消热点数格颜色
            c.BackColor =getBackColor(c);

            old_y_label = (Label)sender;
            old_y_label_color = old_y_label.BackColor;
            old_y_label.BackColor = HotSpotColor;
        }
        void lb_MouseLeave(object sender, EventArgs e)
        {
            if (old_y_label == null)//必须判断，遇到过为空的情况！
                return;
            old_y_label.BackColor = old_y_label_color;
            old_y_label = null;
        }

        void update_y_label()
        {
            for (int i = 0; i < y_lable.Count; ++i)
            {
                if(i==hotnum-1)
                {
                    y_lable[i].ForeColor = Color.Black;
                    y_lable[i].BackColor = Color.DarkGray;
                    continue;
                }
                y_lable[i].ForeColor = Color.DarkGray;
                y_lable[i].BackColor = DefaultBackColor;
            }
        }

        void click_hotnumber(int i)
        {
            if (sta == State.SHOWHINT)
            {
                tip_clear_color_hint(true);
            }
            cell c = getCell(hotpoint);
            c.BackColor = c.bkcolor;
            if(hotnum==i)
                hotnum=0;
            else
                hotnum = i;
            //updatePanel();
        }

        void lb_Click(object sender, EventArgs e)
        {
            Label lb = (Label)sender;
            cell c = getCell(hotpoint);
            c.BackColor = c.bkcolor;
            for(int i=0;i<y_lable.Count;++i)
            {
                if(lb==y_lable[i])
                {
                    if( (i+1)==hotnum)
                    {
                        hotnum = 0;
                        old_y_label_color = DefaultBackColor;
                        return;
                    }
                    click_hotnumber(i + 1);
                    old_y_label_color=Color.DarkGray;

                    c = getCell(hotpoint);//取消热点数格颜色
                    c.BackColor = getBackColor(c);

                    return;
                }
            }
        }

        private void loadConfig()
        {
            //ConfigInfo ci = ConfigInfo.Instance();
            bShowCandidates = (pubfun.str2int(ci["show_candidates", "0"]) == 1);
            bShowTagCandidate =(pubfun.str2int(ci["show_tag_candidates", "0"]) == 1);
            this.toolStripButtonShowCandidates.Checked = bShowCandidates;
            int lvl = pubfun.str2int(ci["lvl", "1"]);
            if (lvl < 1 || lvl > ConfigInfo.lvlList.GetUpperBound(0) + 1)
                lvl = 1;
            this.generatorMenu.Text = "新游戏[" + ConfigInfo.lvlList[lvl - 1] + "]";
            int fmt = pubfun.str2int(ci["PuzzleStringFormat", "3"]);
            switch(fmt)
            {
                case 2:formatType = pubfun.PuzzleStringFormat.FormatMatrix9x9;break;
                case 3:formatType = pubfun.PuzzleStringFormat.FormatTableAscii;break;
                case 1:
                default:formatType = pubfun.PuzzleStringFormat.FormatLine91;break;
            }
            loadColorConfig();
        }


        public void updatePanel()
        {
            for (int y = 1; y <= 9; ++y)
            {
                for (int x = 1; x <= 9; ++x)
                {
                    Point p = new Point(x, y);
                    cell c = getCell(p);
                    int val = m_puzzle[x, y];
                    if (val == 0)
                        c.Text = "";
                    else
                        c.Text = val.ToString();// +"|" + x + "," + y;
                    
                    //c.BackColor=getBackColor(c);

                    for (int j = 0; j < 9; ++j)
                    {
                        pubfun.Flag num = m_puzzle[p, j+1];
                        if (num == pubfun.Flag.none /*|| !bShowCandidates*/)
                            c.m_subcells[j].Visible = false;
                        else if (num == pubfun.Flag.normal)
                        {
                            //c.m_subcells[j].Visible = true;
                            //tagHotNumber(c,j+1,(j==hotnum-1));
                            //if(j==hotnum-1)
                            //    c.m_subcells[j].ForeColor = HotNumberForeColor;
                            //else
                            //    c.m_subcells[j].ForeColor = NumberForeColor;
                        }
                        else if (num == pubfun.Flag.tag)
                        {
                            //c.m_subcells[j].Visible = true;
                            if(bShowTagCandidate)
                                c.m_subcells[j].ForeColor = Color.Gainsboro;
                            else
                                c.m_subcells[j].ForeColor = c.m_subcells[j].bkcolor;
                        }
                    }
                }
            }
            //for (int i = 0; i < y_lable.Count; ++i)
            //{
            //    if ( 
            //        //!bShowCandidates && 
            //        (i + 1) == hotnum)
            //    {
            //        y_lable[i].BackColor = Color.DarkGray;
            //        y_lable[i].ForeColor = Color.Black;
            //    }
            //    else
            //    {
            //        y_lable[i].BackColor = DefaultBackColor;
            //        y_lable[i].ForeColor = Color.DarkGray;
            //    }
            //}
            //处理颜色提示
            tip_show_color_hint();

        }

        //从面板坐标得到所在的小九宫
        public cellset getCellset(Point p)
        {
            int x = (p.X - 1) / 3; // 0 , 1 , 2
            int y = (p.Y - 1) / 3; // 0 , 1 , 2
            //Debug.WriteLine("getCellset("+p.X+","+p.Y+")=cellsets["+(x+y*3)+"]");
            return m_cellsets[x + y * 3];
        }
        //从面板坐标得到小数格
        public cell getCell(Point p)
        {
            cellset cs = getCellset(p);

            Point baseXY = pubfun.basepoints[cs.idx - 1];

            int x = (p.X - baseXY.X); // 0 , 1 , 2
            int y = (p.Y - baseXY.Y); // 0 , 1 , 2
            //Debug.WriteLine("getCell(" + p.X + "," + p.Y + ")=m_cells[" + (x + y * 3) + "]");
            return cs.m_cells[x + y * 3];
        }

        public void doClickSubCell(subcell sc)
        {
            tip_clear_color_hint(true);//如果是提示状态，退出提示模式
            hotpoint = sc.xy;

            cell c = getCell(sc.xy);
            if (c.solid)
                return;
            //Debug.WriteLine("ClickSubCell:<" + sc.xy + "><" + sc.id + ">");
            if (m_puzzle[sc.xy] != 0) //如果在已经有数字的前提下，再次点击，则表示要添加候选数
            {
                if (sc.id == m_puzzle[sc.xy]) //如果相等，说明是点了提示格
                {
                    sc.BackColor = getBackColor(sc);// sc.bkcolor;
                    sc.ml_bkcolor = sc.bkcolor;
                    c.BackColor = getBackColor(c);// c.bkcolor;
                    c.ml_bkcolor = c.bkcolor;
                    updatePanel();
                    return;
                }
                int old = m_puzzle[sc.xy];
                Debug.WriteLine("重复点击，取消原有设置数，重新添加"+old+"和"+sc.id+"为"+pubfun.strPoint(sc.xy)+"的候选数！\n");
                m_puzzle[sc.xy] = 0;
                m_puzzle[sc.xy, old] = pubfun.Flag.normal;
                c.m_subcells[old - 1].Visible = true;
                if(old!=sc.id)
                {
                    m_puzzle[sc.xy, sc.id] = pubfun.Flag.normal;
                    sc.Visible = true;
                }
                
                updatePanel();
            }
            else
            {
                m_puzzle[sc.xy] = sc.id;
                String str = "手动设置" + pubfun.strPoint(sc.xy) + "的数字为" + sc.id;
                List<operation> oplist = new List<operation>();
                oplist.Add(new operation(operation.SolveHelper.Manual, operation.opname.set_number, new Point[] { sc.xy }, new int[] { sc.id }, str));
                while (true)
                {
                    if (m_ops.Count > m_current_op)
                        m_ops.RemoveAt(m_ops.Count - 1);
                    else
                        break;
                }
                m_ops.Add(oplist);
                m_current_op++;

                updatePanel();
                if (m_puzzle.getPuzzleStatus() == puzzle.Status.SUCCESS)
                {
                    GameFinished();
                }
            }
        }
        public void doRClickSubCell(subcell sc)
        {
            tip_clear_color_hint(true);//如果是提示状态，退出提示模式
            hotpoint = sc.xy;
            //Debug.WriteLine("RClickSubCell:<" + sc.xy + "><" + sc.id + ">");
            pubfun.Flag v = m_puzzle[sc.xy, sc.id];
            String str="";
            operation.opname opn = operation.opname.set_candidate_tag;
            if(v== pubfun.Flag.normal)
            {
                m_puzzle[sc.xy, sc.id] = pubfun.Flag.tag;
                str="手动标记取消" + pubfun.strPoint(sc.xy) + "的候选数字" + sc.id;
                opn=operation.opname.set_candidate_tag;
                List<int[]> nodes = new List<int[]>();
                nodes.Add(new int[] { 1, sc.xy.X, sc.xy.Y, sc.id });
            }
            else if(v==pubfun.Flag.tag)
            {
                m_puzzle[sc.xy, sc.id] = pubfun.Flag.normal;
                str="手动标记添加" + pubfun.strPoint(sc.xy) + "的候选数字" + sc.id;
                opn = operation.opname.set_candidate_untag;
                List<int[]> nodes = new List<int[]>();
                nodes.Add(new int[] { 1, sc.xy.X, sc.xy.Y, sc.id });
            }

             
            List<operation> oplist = new List<operation>();
            oplist.Add(new operation(operation.SolveHelper.Manual,opn , new Point[] { sc.xy }, new int[] { sc.id }, str));
            while (true)
            {
                if (m_ops.Count > m_current_op)
                    m_ops.RemoveAt(m_ops.Count - 1);
                else
                    break;
            }
            m_ops.Add(oplist);
            m_current_op++;

            //updatePanel();


        }

        public void doRClickCell(cell c)
        {
            tip_clear_color_hint(true);//如果是提示状态，退出提示模式
            hotpoint = c.xy;
            if(!bShowCandidates)
            {
                //智能选择位置显示
                show_tab_pop(true);
            }
        }
        public void doClickCell(cell c)
        {
            tip_clear_color_hint(true);//如果是提示状态，退出提示模式
            hotpoint = c.xy;
            //Debug.WriteLine("ClickCell:<" + c.xy + "><" + c.Text + ">");
            if (m_puzzle[c.xy] == 0)
            {
                if (bShowCandidates)//显示候选数时点空白格
                {
                    return;
                }
                if (hotnum == 0)
                    hotnum = 1;
                doClickSubCell(c.m_subcells[hotnum-1]);
                return;
            }
            String str = "手动取消对" + pubfun.strPoint(c.xy) + "的数字" + m_puzzle[c.xy] + "的设置";
            List<operation> oplist=new List<operation>();
            oplist.Add( new operation(operation.SolveHelper.Manual, operation.opname.unset_number, new Point[] { c.xy }, new int[] { m_puzzle[c.xy] }, str) );
            while (true)
            {
                if (m_ops.Count > m_current_op)
                    m_ops.RemoveAt(m_ops.Count - 1);
                else
                    break;
            }
            m_ops.Add(oplist);
            m_current_op++;

            m_puzzle[c.xy] = 0;
            updatePanel();
            if (m_puzzle.getPuzzleStatus() == puzzle.Status.SUCCESS)
            {
                MessageBox.Show("You Win!!!");
            }
        }

        private int undoOperations(List<operation> ops)
        {
            undo_step_count++;//统计步骤数
            //反操作
            foreach (operation op in ops)
            {
                switch (op.m_op)
                {
                    case operation.opname.set_candidate_none://将候选数恢复为普通状态
                        foreach (Point p in op.m_points)
                        {
                            foreach (int val in op.values)
                            {
                                m_puzzle[p, val] = pubfun.Flag.normal;
                            }
                        }
                        break;
                    case operation.opname.set_candidate_tag://将候选数恢复为normal
                        foreach (Point p in op.m_points)
                        {
                            foreach (int val in op.values)
                            {
                                m_puzzle[p, val] = pubfun.Flag.normal;
                            }
                        }
                        break;
                    case operation.opname.set_candidate_untag://将候选数置为tag
                        foreach (Point p in op.m_points)
                        {
                            foreach (int val in op.values)
                            {
                                m_puzzle[p, val] = pubfun.Flag.tag;
                            }
                        }
                        break;
                    case operation.opname.set_number://取消对数格的设置
                        foreach (Point p in op.m_points)
                        {
                            m_puzzle[p] = 0;
                            cell c=getCell(p);
                            c.BackColor = c.bkcolor;
                        }
                        break;
                    case operation.opname.unset_number://恢复对数格数字的选择
                        foreach (Point p in op.m_points)
                        {
                            m_puzzle[p] = op.values[0];
                        }
                        break;
                }
                if (op.helper != operation.SolveHelper.Manual)
                    setStatusText(op.info,0);
            }
            return ops.Count;
        }

        private int redoOperations(List<operation> ops)
        {
            //正操作
            foreach (operation op in ops)
            {
                switch (op.m_op)
                {
                    case operation.opname.set_candidate_none://将候选数取消
                        foreach (Point p in op.m_points)
                        {
                            foreach (int val in op.values)
                            {
                                m_puzzle[p, val] = pubfun.Flag.none;
                            }
                        }
                        break;
                    case operation.opname.set_candidate_tag://将候选数恢复为tag
                        foreach (Point p in op.m_points)
                        {
                            foreach (int val in op.values)
                            {
                                m_puzzle[p, val] = pubfun.Flag.tag;
                            }
                        }
                        break;
                    case operation.opname.set_candidate_untag://将候选数置为normal
                        foreach (Point p in op.m_points)
                        {
                            foreach (int val in op.values)
                            {
                                m_puzzle[p, val] = pubfun.Flag.normal;
                            }
                        }
                        break;
                    case operation.opname.set_number://恢复对数格数字的选择
                        foreach (Point p in op.m_points)
                        {
                            m_puzzle[p]=op.values[0];
                        }
                        break;
                    case operation.opname.unset_number://取消对数格的设置
                        foreach (Point p in op.m_points)
                        {
                            m_puzzle[p]=0;
                        }
                        break;
                }
                if (op.helper != operation.SolveHelper.Manual)
                    setStatusText(op.info, 0);
            }
            return ops.Count;
        }

        private int undoSingle()
        {
            tip_clear_color_hint(false);
            int ret = 0;
            if (m_current_op > 0 && m_ops.Count>=m_current_op)
            {
                List<operation> ops = m_ops[m_current_op - 1];
                m_current_op--;

                ret=undoOperations(ops);

                undo_count++;
            }
            updatePanel();
            return ret;
        }

        private int redoSingle()
        {
            //if(undo_count>0) undo_count--;
            int ret = 0;
            if (m_current_op >= 0 && m_ops.Count > m_current_op)
            {
                List<operation> ops = m_ops[m_current_op];
                m_current_op++;

                ret = redoOperations(ops);

            }
            updatePanel();
            if (m_puzzle.getPuzzleStatus() == puzzle.Status.SUCCESS)
            {
                GameFinished();
            }
            return ret;
        }

        private void buttonCopy_Click(object sender, EventArgs e)
        {
            copyToClipboard();
        }

        private void toolStripMenuItemCopyOriPuzzle_Click(object sender, EventArgs e)
        {
            Clipboard.SetDataObject(pubfun.formatPuzzleString(strCurrentSudoku,formatType), true);
            //MessageBox.Show("此题的初始局面已经复制到剪贴板！");
            setStatusText("此题的初始局面已经复制到剪贴板！", 0);
        }

        public void copyToClipboard()
        {
            Clipboard.SetDataObject(pubfun.formatPuzzleString(m_puzzle.exportPuzzle(), formatType), true);
            //MessageBox.Show("当前局面已经复制到剪贴板！");
            setStatusText("当前局面已经复制到剪贴板！", 0);
        }

        public bool pasteFromClipboard()
        {
            IDataObject iData = Clipboard.GetDataObject();
            if(iData.GetDataPresent(DataFormats.Text)) 
            {
                String str = ((String)iData.GetData(DataFormats.Text)).Replace("\r", "");
                str = str.Replace("\n", "");
                if (str.IndexOf('+') >= 0 && str.IndexOf('-') >= 0 && str.IndexOf('|') >= 0)
                {
                    str = str.Replace("|", "");
                    str = str.Replace("-", "");
                    str = str.Replace("+", "");
                }
                if(str.Length>81)
                {
                    str=str.Substring(0,81);
                }
                while (str.Length < 81)
                    str += ".";
                //if(str.Length==81)
                {
                    if (startPuzzle(str))
                        //this.Text = get_lvl_str(str) + " " + this.Text;
                        StartGetLvlThread();
                    return true;
                }
            }
            return false;
        }

        private void savePuzzle()
        {
            SaveFileDialog dlg = new SaveFileDialog();
            //dlg.FileName = "d:\\puzzle.txt";
            dlg.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            if (dlg.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            String strPuzzle = m_puzzle.exportPuzzle();
            String strFilename = dlg.FileName;
            StreamWriter sr = new StreamWriter(strFilename, false, Encoding.GetEncoding("GB2312"));
            sr.Write(strPuzzle);
            sr.Close();

        }

        private void loadPuzzle()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            //dlg.FileName = "d:\\puzzle.txt";
            dlg.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
            if (dlg.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            String strFilename = dlg.FileName;
            StreamReader sr = new StreamReader(strFilename, Encoding.GetEncoding("GB2312"));
            String strContent = sr.ReadToEnd();
            sr.Close();
            strContent = strContent.Replace("\r", "");
            strContent = strContent.Replace("\n", "");
            if (startPuzzle(strContent))
                StartGetLvlThread(); // this.Text = get_lvl_str(strContent) + " " + this.Text;
        }

        private void toolStripMenuItemGenerateRandom_Click(object sender, EventArgs e)
        {
            String res = "";
            String str = "";
            SudokuGenerator generator = new SudokuGenerator();
            str = generator.do_dlx_generator(ref res);
            
            nLvlInfo = 0;
            Debug.WriteLine("生成新局面:\r\n" + str);
            startPuzzle(str);
            StartGetLvlThread();

        }

        private void startNewPuzzle()
        {
            String str;
            SudokuGenerator generator = new SudokuGenerator();
            String res="";
            nLvlInfo = pubfun.str2int(ci["lvl", "1"]);
            String strlibfile = ci["lvl_" + nLvlInfo + "_xml", "lvl" + nLvlInfo + ".xml"];
            SudokuLibrary sl = new SudokuLibrary(strlibfile, nLvlInfo);
            dlx_solver ds = new dlx_solver();
            if (sl.Count > 0)
            {
                XmlNode xn = sl.randGetSudoku();
                if(xn!=null)
                {
                    str = xn.Name;
                    //sl.removeSudoku(xn);    //将题目的移除放到解题完成时
                    //sl.Save();
                    SudokuLibrary.removeSudokuPrefix(ref str);


                    //SudokuLibrary slold = new SudokuLibrary(ci["lvl_0_xml", "lvl0.xml"], 0);
                    //xn = slold.insertSudoku(str, true);
                    res = ds.do_solve(str);
                }
                else
                {
                    str = generator.do_dlx_generator(ref res);
                    //i = get_lvl(str);
                    StartGetLvlThread();
                    nLvlInfo = 0;
                }
            }
            else
            {
                str = generator.do_dlx_generator(ref res);
                //i = get_lvl(str);
                StartGetLvlThread();
                nLvlInfo = 0;
            }

            Debug.WriteLine("生成新局面:\r\n" + str);
            if (startPuzzle(str))
            {
                if (nLvlInfo > 0 && nLvlInfo <= ConfigInfo.lvlList.Length)
                {
                    this.Text = get_lvl_str(nLvlInfo) + " " + this.Text;
                }
            }
        }

        private Thread chkLvlThread;
        protected void StartGetLvlThread()
        {
            if (chkLvlThread != null && chkLvlThread.IsAlive)
            {
                try
                {
                    chkLvlThread.Abort();
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.ToString());
                }
            }
            chkLvlThread = new Thread(new ThreadStart(threadMain));
            chkLvlThread.Start();
        }

        private String strLvlInfo = "";
        private int nLvlInfo = 0;
        private void threadMain()
        {
            //需要对标题和题目变量进行加锁
            try //捕捉异常，丢弃异常！
            {
                int i = get_lvl(strCurrentSudoku);
                if (i > 0 && i <= ConfigInfo.lvlList.Length)
                {
                    nLvlInfo = i;
                    strLvlInfo = get_lvl_str(nLvlInfo);
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());
            }
        }

        private int get_lvl(String str)
        {
            int lvl= solver.get_lvl(str);
            if (lvl > ConfigInfo.lvlList.Length)
                lvl = ConfigInfo.lvlList.Length;
            return lvl;
        }
        private String get_lvl_str(int i)
        {
            if (i > 0 && i <= ConfigInfo.lvlList.Length)
            {
                return ConfigInfo.lvlList[i - 1];
            }
            return "";
        }
        private String get_lvl_str(String str)
        {
            int i = get_lvl(str);
            if (i > 0 && i <= ConfigInfo.lvlList.Length)
            {
                return  ConfigInfo.lvlList[i - 1] ;
            }
            return "";
        }

        private void puzzle_changed(List<int[]> nodes)
        {
            //注意在这里输出debug信息会非常的慢
            foreach(int[] node in nodes)
            {
                Point p = new Point(node[1], node[2]);
                if (!bShowCandidates )
                {
                    //如果是提示状态，那么对所有关键候选数所在数格应该给与提示
                    if (sta == State.SHOWHINT)
                    {
                        bool has_import_cand = false;                        
                        cell cc = getCell(p);
                        foreach (subcell sc in cc.m_subcells)
                        {
                            if (sc.BackColor != cc.BackColor)
                            {
                                has_import_cand = true;
                                break;
                            }
                        }
                        if (!has_import_cand)
                            continue;
                    }
                    else
                    {
                        if (p != hotpoint)
                            continue;
                    }
                }
                cell c = getCell(p);
                switch(node[0])
                {
                    case 0:
                        //Debug.WriteLine("收到数格"+pubfun.strPoint(p)+"的变化通知");
                        if(m_puzzle[p]==0)
                        {
                            for (int cand = 1; cand <= 9;++cand )
                            {
                                if(m_puzzle[p,cand]!=pubfun.Flag.none)
                                {
                                    c.m_subcells[cand - 1].Visible = true;
                                }
                            }
                            c.Text = "";
                        }
                        else
                        {
                            for (int cand = 1; cand <= 9; ++cand)
                            {
                                c.m_subcells[cand - 1].Visible = false;
                            }
                            c.Text = m_puzzle[p].ToString();
                            c.BackColor=getBackColor(c);
                        }
                        break;
                    case 1:
                        {
                            int cand = node[3];
                            //Debug.WriteLine("收到数格" + pubfun.strPoint(p) + "的候选数" + cand + "的变化通知");
                            if (m_puzzle[p] == 0)
                            {
                                switch(m_puzzle[p, cand] )
                                {
                                    case pubfun.Flag.none:
                                        c.m_subcells[cand - 1].Visible = true;
                                        break;
                                    case pubfun.Flag.normal:
                                        c.m_subcells[cand - 1].ForeColor = Color.Black;
                                        c.m_subcells[cand - 1].BackColor = getBackColor(c.m_subcells[cand - 1]);
                                        c.m_subcells[cand - 1].Visible = true;
                                        break;
                                    case pubfun.Flag.tag:
                                        //c.m_subcells[cand - 1].ForeColor = Color.DarkGray;
                                        if (bShowTagCandidate)
                                            c.m_subcells[cand - 1].ForeColor = Color.Gainsboro;
                                        else
                                        {
                                            c.m_subcells[cand - 1].ForeColor = c.m_subcells[cand - 1].bkcolor;
                                            c.m_subcells[cand - 1].BackColor = getBackColor(c.m_subcells[cand - 1]);
                                        }

                                        c.m_subcells[cand - 1].Visible = true;
                                        break;
                                }
                                if (c.xy == hotpoint)//解决热点数显示时，标记候选数的背景应该与热点数相同的问题
                                    c.m_subcells[cand - 1].BackColor = HotSpotColor;
                            }
                        }
                        break;
                }
            }
            return;
        }

        private String strCurrentSudoku;
        private int nClueNumber;

        public bool startPuzzle(String str)
        {
            //将热点数复位
            hotnum = 0;
            //颜色和数值复位
            foreach (cellset cs in m_cellsets)
            {
                foreach (cell c in cs.m_cells)
                {
                    c.solid = false;
                    m_puzzle[c.xy] = 0;
                    foreach(subcell sc in c.m_subcells)
                    {
                        sc.BackColor = sc.bkcolor;
                    }
                }
            }

            dlx_solver ds = new dlx_solver();
            String strResult = ds.do_solve(str);
            int scnt = ds.solution_count(str);
            Debug.WriteLine("DLX:" + strResult);
            if(scnt==0)
            {
                MessageBox.Show("无解局面！");
                return false;
            }
            if (scnt > 1)
            {
                MessageBox.Show("此题有不止一个解！");
                return false;
            }

            strCurrentSudoku = pubfun.formatPuzzleString(str,pubfun.PuzzleStringFormat.FormatLine91);
            nClueNumber = 0;//统计初始数
            foreach(Char ch in strCurrentSudoku.ToCharArray())
            {
                if(ch <= '9' && ch >='1')
                {
                    nClueNumber++;
                }
            }
            m_puzzle2 = new puzzle();
            m_puzzle2.loadPuzzle(strResult.ToCharArray());

            if(sta==State.INPUTING)
                changeStateInputOver();
            sta = State.PLAYING;
            this.tabPop.Visible = false;

            m_ops = new List<List<operation>>();
            m_current_op = 0;
            tip_count = 0;
            undo_count = 0;
            undo_step_count = 0;

            m_puzzle.loadPuzzle(str.ToCharArray());
            m_puzzle.puzzleChanged+=puzzle_changed;//注册变化事件通知

            Debug.WriteLine("开始游戏：\r\n" + m_puzzle.exportPuzzle());
            Debug.WriteLine("答案：\r\n" + m_puzzle2.exportPuzzle());

            this.Text =AssemblyProduct + m_puzzle.exportPuzzleCompact();
            m_solver = new solver(m_puzzle);
            if ( strResult.Length > 0)
            {
                m_solver.strResult = strResult;
            }
            foreach(cellset cs in m_cellsets)
            {
                foreach(cell c in cs.m_cells)
                {
                    if (m_puzzle[c.xy] > 0)
                    {
                        c.ForeColor = SolidNumberForeColor;
                        c.solid = true;
                    }
                    else
                    {
                        c.ForeColor = NumberForeColor;
                        c.solid = false;
                        foreach(subcell sc in c.m_subcells)
                        {
                            sc.Font = scFont; //恢复可能被提示功能标记删除的候选数
                        }
                    }
                    c.BackColor = getBackColor(c);
                }
            }
            setStatusText("",0);
            show_all_candidates(bShowCandidates);
            updatePanel();
            dtstart = DateTime.Now;
            dtsecs = 0;
            timerGameWatch.Start();
            timerStatistics.Start();

            if (ci.bShowHotspot)
                hotpoint = hotpoint;
            return true;
        }

        private void GameFinished()
        {
            setStatusText("题目已经完成",0);
            TimeSpan ts=DateTime.Now - dtstart;
            timerGameWatch.Stop();
            timerStatistics.Stop();
            String str = "开始时间：" + dtstart.ToString() + "\r\n" +
                "结束时间：" + DateTime.Now.ToString() + "\r\n" +
                "耗时：" + (ts.Hours > 0 ? (ts.Hours + "个小时") : "") + (ts.Minutes > 0 ? (ts.Minutes + "分") : "") + ts.Seconds + "秒" + "\r\n" +
                "使用提示次数：" + tip_count + "次\r\n";
            if(undo_step_count>0 || undo_count>0)
                str+="使用撤销操作：" + undo_count + "次\r\n撤销步数：" + undo_step_count + "步\r\n";
            Debug.WriteLine(str);
            if(pubfun.str2int(ci["game_finished_statistics","1"]) > 0)
            {
                DialogResult dr = MessageBox.Show(str, "题目完成！是否复制解题步骤？", MessageBoxButtons.YesNo);
                if (dr == DialogResult.Yes)
                {
                    try
                    {
                        //TODO:这里存在出现 异常的可能（用户反馈）先临时捕捉异常不进行处理
                        copySteps();
                    }
                    catch (Exception)
                    {
                    }
                }
            }

            SudokuLibrary slold = new SudokuLibrary(ci["lvl_" + nLvlInfo + "_xml", "lvl" + nLvlInfo + ".xml"], 0);
            //将题目从原题库移除
            XmlNode oldnode=slold.getSudoku(strCurrentSudoku);
            if(oldnode!=null) //对于复制来的题目，是很可能查不到的
                slold.removeSudoku(oldnode);
            SudokuLibrary sl = new SudokuLibrary(ci["top_"+nLvlInfo+"_xml", "top"+nLvlInfo+".xml"], 0);
            XmlNode xn = sl.getSudoku(strCurrentSudoku);
            if(xn==null)
                xn=sl.insertSudoku(strCurrentSudoku, true);
            if(xn!=null)
            {
                XmlElement xe = (XmlElement)xn;
                //记录时间
                xe.SetAttribute("seconds", dtsecs.ToString()); 
                //还需要记录难度 (解题步骤?)
                xe.SetAttribute("lvl", nLvlInfo.ToString());
                xe.SetAttribute("tips", tip_count.ToString());
                xe.SetAttribute("undo_count", undo_count.ToString());
                xe.SetAttribute("undo_steps", undo_step_count.ToString());
                xe.SetAttribute("datetime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                sl.Save();
            }
            if (pubfun.str2int(ci["game_finished_scorelist", "1"]) > 0)
            {
                if (!showScoreListDialog() && pubfun.str2int(ci["auto_play_next"]) > 0)
                {
                    startNewPuzzle();
                }
            }
            else
            {
                if (pubfun.str2int(ci["auto_play_next"]) > 0)
                {
                    startNewPuzzle();
                }
            }
        }

        private void resetPuzzle()
        {
            foreach (cellset cs in m_cellsets)
            {
                foreach (cell c in cs.m_cells)
                {
                    if (!c.solid)
                    {
                        m_puzzle[c.xy] = 0;
                    }
                }
            }
            String str = m_puzzle.exportPuzzle();
            String strResult = m_solver.strResult;
            String title = this.Text;
            startPuzzle(str);
            this.Text = title;

            m_solver.strResult = strResult;
        }

        private bool singleStepSolvePuzzle()
        {
            m_solver.run(1);

            while (true)
            {
                if (m_ops.Count > m_current_op)
                    m_ops.RemoveAt(m_ops.Count - 1);
                else
                    break;
            }
            if (m_solver.opsteps.Count>0)
            {
                m_ops.Add(m_solver.opsteps[m_solver.opsteps.Count-1]);//添加最后的几个
                m_current_op++;
            }

            updatePanel();
            if (m_puzzle.getPuzzleStatus() == puzzle.Status.SUCCESS)
            {
                GameFinished();
                return true;
            }
            return false;
        }

        private bool autosolvePuzzle()
        {
            if(undoErrorStep(true))
            {
                MessageBox.Show("当前解题步骤存在错误，请先取消错误步骤!");
                return false;
            }
            while (true)
            {
                if (m_ops.Count > m_current_op)
                    m_ops.RemoveAt(m_ops.Count - 1);
                else
                    break;
            }
            bool ret = true;
            m_solver.isSingleStep = true;
            while (ret)
            {
                ret = m_solver.run(1);//点一次执行一步
                tip_count++;
                if (m_solver.opsteps.Count > 0 && ret)
                {
                    m_ops.Add(m_solver.opsteps[m_solver.opsteps.Count - 1]);//添加最后的几个
                    m_current_op++;
                }
            }
            if (m_puzzle.getPuzzleStatus() != puzzle.Status.SUCCESS)
            {
                updatePanel();
                MessageBox.Show("错误，无解局面!");
                return false;
            }
            updatePanel();
            GameFinished();
            Debug.WriteLine("autosolver return " + ((ret) ? "ok" : "fail"));
            return true;
        }

        #region 程序集属性访问器

        public string AssemblyTitle
        {
            get
            {
                object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
                if (attributes.Length > 0)
                {
                    AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
                    if (titleAttribute.Title != "")
                    {
                        return titleAttribute.Title;
                    }
                }
                return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
            }
        }

        public string AssemblyVersion
        {
            get
            {
                return Assembly.GetExecutingAssembly().GetName().Version.ToString();
            }
        }

        public string AssemblyDescription
        {
            get
            {
                object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
                if (attributes.Length == 0)
                {
                    return "";
                }
                return ((AssemblyDescriptionAttribute)attributes[0]).Description;
            }
        }

        public string AssemblyProduct
        {
            get
            {
                object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false);
                if (attributes.Length == 0)
                {
                    return "";
                }
                return ((AssemblyProductAttribute)attributes[0]).Product;
            }
        }

        public string AssemblyCopyright
        {
            get
            {
                object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
                if (attributes.Length == 0)
                {
                    return "";
                }
                return ((AssemblyCopyrightAttribute)attributes[0]).Copyright;
            }
        }

        public string AssemblyCompany
        {
            get
            {
                object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
                if (attributes.Length == 0)
                {
                    return "";
                }
                return ((AssemblyCompanyAttribute)attributes[0]).Company;
            }
        }
        #endregion


        void doKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            //Debug.WriteLine("KeyDown:" + e.KeyCode.ToString() + "\r\n" + e.KeyData.ToString() + "\r\n" + e.KeyValue);
            if (e.KeyCode == Keys.Left)
            {
                Point p = hotpoint;
                --p.X;
                if (p.X < 1) p.X = 9;
                hotpoint = p;
            }
            if (e.KeyCode == Keys.Right)
            {
                Point p = hotpoint;
                ++p.X;
                if (p.X > 9) p.X = 1;
                hotpoint = p;
            }
            if (e.KeyCode == Keys.Up)
            {
                Point p = hotpoint;
                --p.Y;
                if (p.Y < 1) p.Y = 9;
                hotpoint = p;
            }
            if (e.KeyCode == Keys.Down)
            {
                Point p = hotpoint;
                ++p.Y;
                if (p.Y > 9) p.Y = 1;
                hotpoint = p;
            }
        }

        public void doKeyUp(object sender, KeyEventArgs e)
        {
            //Debug.WriteLine("KeyUp:" +  e.KeyCode.ToString() + "\r\n" + e.KeyData.ToString() + "\r\n" + e.KeyValue);
            if(e.Control && e.KeyCode== Keys.C)
            {
                copyToClipboard();
            }
            if(e.Control && e.KeyCode== Keys.V)
            {
                pasteFromClipboard();
            }
            if (e.Control && e.KeyCode == Keys.N)
            {
                startNewPuzzle();
            }
            if (e.Control && e.KeyCode == Keys.H)
            {
                getTip();
            }
            if (e.Control && e.KeyCode == Keys.U)
            {
                undoSingle();
            }
            if (e.Control && e.KeyCode == Keys.R)
            {
                redoSingle();
            }
            if (e.Control && e.KeyCode == Keys.T)
            {
                doTest();
            }
            //回车表示填写当前热点数
            if (hotnum>0 && e.KeyCode == Keys.Enter)
            {
                cell c = getCell(hotpoint);
                if (!c.solid)
                {
                    if (!e.Control)
                    {
                        if (m_puzzle[c.xy] != 0)
                            doClickCell(c);
                        else
                            doClickSubCell(c.m_subcells[hotnum - 1]);//可能需要传入ctrl状态！
                    }
                    else
                        set_candidate(c.xy, hotnum, false);
                }
            }
            //0和空格是重新计算当前数格的候选数
            if(e.KeyCode == Keys.Space ||e.KeyCode == Keys.D0  || e.KeyCode == Keys.NumPad0 )
            {
                cell c = getCell(hotpoint);
                //if(bShowCandidates)
                {
                    for(int i=0;i<9;++i)
                    {
                        if(m_puzzle[c.xy,i+1]!= pubfun.Flag.none )
                        {
                            m_puzzle[c.xy, i + 1] = pubfun.Flag.normal;
                            c.m_subcells[i].Visible = true;
                        }
                        else
                            c.m_subcells[i].Visible = false;
                    }
                }
            }
            //del删除全部候选数（普通模式）或标记所有候选数为删除（候选数模式）
            if(e.KeyCode == Keys.Delete)
            {
                cell c = getCell(hotpoint);
                if(c.Text!="" && !c.solid)
                {
                    m_puzzle[c.xy] = 0;
                }
                foreach(subcell sc in c.m_subcells)
                {
                    if (bShowCandidates)
                    {
                        if(sc.Visible)
                        {
                            m_puzzle[c.xy, pubfun.str2int(sc.Text)] = pubfun.Flag.tag;
                        }
                    }
                    else
                        sc.Visible = false;
                }
            }
            for (int i = 0; i < 9; ++i)
            {
                if (e.KeyCode == Keys.D1 + i || e.KeyCode == Keys.NumPad1 + i)
                {
                    //if (tabPop.Visible)
                        tabPop.Visible = false;
                    int nKey=i+1;
                    String keychar=nKey.ToString();
                    cell c = getCell(hotpoint);
                    c.BackColor = c.bkcolor;//恢复热点数格的背景色
                    old_y_label = null; //避免数格移动的问题
                    click_hotnumber(i + 1);//hotnum = i + 1;
                    if(e.Control)//ctrl-数字表示切换热点数字
                        break; 
                    if(e.Shift)//alt-数字表示填写数字
                    {
                        if(m_puzzle[c.xy,nKey]!= pubfun.Flag.none)
                        {
                            doClickSubCell(c.m_subcells[i]);
                        }
                        break;
                    }

                    if(!ci.bUseKeyboard) //如果未配置使用键盘，则不进行后续操作
                        break;

                    //c = getCell(hotpoint);
                    if(c.solid)
                        break ;
                    if (!e.Control)
                    {

//    a）无该候选数显示时按数字表示添加该候选数，添加可能会因为在其他可见的数格已经填写该数字而不能添加
//    b）已经有候选数时，按数字表示删除该候选数，但是如果只有一个候选数，则是表示填写该数字
//    c）只有一个候选数显示时，如果是从两候选数变为一个，则该候选数自动选为填写数，如果是从已经填数变成一个候选数时，则不自动填写
//    d）已经填写数时，再按该数表示该数变为候选数
//    e）已经填写数时，再按其他数，表示两数都变为候选数

                        List<subcell> scs = new List<subcell>();
                        if (c.Text == "")
                        {
                            foreach (subcell sc in c.m_subcells) 
                            {
                                if (sc.Visible && m_puzzle[sc.xy, pubfun.str2int(sc.Text)] == pubfun.Flag.normal) //可见候选数
                                    scs.Add(sc);
                            }
                            //a)
                            if (scs.Count == 0 && m_puzzle[c.xy,nKey] != pubfun.Flag.none)
                            {
                                c.m_subcells[i].Visible = true;
                                m_puzzle[c.xy, nKey] = pubfun.Flag.normal;//添加的一律设置为normal
                            }
                            //b)
                            else if (c.m_subcells[i].Visible)
                            {
                                if (scs.Count == 1 && scs[0].Text == keychar)
                                {
                                    doClickSubCell(c.m_subcells[i]);
                                }
                                else
                                {
                                    if (m_puzzle[c.xy, nKey] != pubfun.Flag.none)
                                        doRClickSubCell(c.m_subcells[i]);
                                    //old c)
                                }
                            }
                            else //a)
                            {
                                if(m_puzzle[c.xy,nKey] != pubfun.Flag.none)
                                {
                                    c.m_subcells[i].Visible = true;
                                    if (m_puzzle[c.xy, nKey] != pubfun.Flag.normal)
                                    {
                                        List<operation> oplist = new List<operation>();
                                        operation.opname opn = operation.opname.set_candidate_tag;
                                        String str = "手动标记添加" + pubfun.strPoint(c.xy) + "的候选数字" + c.m_subcells[i].id;
                                        oplist.Add(new operation(operation.SolveHelper.Manual, opn, new Point[] { c.xy }, new int[] { c.m_subcells[i].id }, str));

                                        m_puzzle[c.xy, nKey] = pubfun.Flag.normal;//添加的一律设置为normal
                                    }
                                }
                            }
                            //c)
                            if (c.Text == "")
                            {
                                scs = new List<subcell>();
                                foreach (subcell sc in c.m_subcells)
                                {
                                    if (sc.Visible && m_puzzle[sc.xy, pubfun.str2int(sc.Text)] == pubfun.Flag.normal) //可见候选数
                                        scs.Add(sc);
                                }
                                if (scs.Count == 1)
                                {
                                    doClickSubCell(scs[0]);
                                }
                            }
                        }
                        else
                        {
                            // d) e)
                            String oldchar=c.Text;

                            String str = "手动取消对" + pubfun.strPoint(c.xy) + "的数字" + m_puzzle[c.xy] + "的设置";
                            List<operation> oplist = new List<operation>();
                            oplist.Add(new operation(operation.SolveHelper.Manual, operation.opname.unset_number, new Point[] { c.xy }, new int[] { m_puzzle[c.xy] }, str));
                            while (true)
                            {
                                if (m_ops.Count > m_current_op)
                                    m_ops.RemoveAt(m_ops.Count - 1);
                                else
                                    break;
                            }
                            m_ops.Add(oplist);
                            m_current_op++;

                            m_puzzle[c.xy] = 0;
                            //c.Text = "";
                            //if (!bShowCandidates)
                            {
                                foreach(subcell sc in c.m_subcells)
                                {
                                    if(sc.Visible)
                                    {
                                        if (sc.Text != keychar && sc.Text != oldchar)
                                        {
                                            if (!bShowCandidates)
                                            {
                                                sc.Visible=false;
                                            }
                                            else
                                            {
                                                m_puzzle[c.xy, pubfun.str2int(sc.Text)] = pubfun.Flag.tag;
                                                sc.ForeColor = getBackColor(sc); //标记抹去sc
                                            }
                                        }
                                    }
                                }
                            }
                            //普通模式下，在前一个数填入时，可能导致部分已经标记的候选数被抹去，需要补回
                            if (!bShowCandidates)
                            {
                                int old=pubfun.str2int(oldchar);
                                foreach(number num in m_puzzle.get_group(c.xy))
                                {
                                    if(num.candidates().Length==0)
                                        continue;
                                    cell cc = getCell(num.xy);
                                    List<subcell> sclist = new List<subcell>();
                                    foreach(subcell sc in cc.m_subcells)
                                    {
                                        if (sc.Visible )
                                            sclist.Add(sc);
                                    }
                                    if (sclist.Count > 0)
                                    {
                                        if (m_puzzle[num.xy, old] != pubfun.Flag.none)
                                        {
                                            cc.m_subcells[old - 1].Visible = true;
                                            cc.m_subcells[old - 1].BackColor = getBackColor(cc.m_subcells[old - 1]);
                                        }
                                    }
                                }
                            }
                        }

                        //if(m_puzzle[c.xy]!=0)
                        //    doClickCell(c);
                        //else
                        //    doClickSubCell(c.m_subcells[i]);//可能需要传入ctrl状态！
                    }
                    else
                        set_candidate(c.xy, hotnum, false);
                    break;//找到了就无需判断后面的了
                }
            }
        }

        private void set_candidate(Point p,int cand,bool emitEvent)
        {
            List<int[]>nodes =new List<int[]>();
            nodes.Add(new int[] { 0, hotpoint.X, hotpoint.Y });
            cell c = getCell(p);
            if (cand > 0)
            {
                int old = m_puzzle[p];
                if (old > 0)
                {
                    m_puzzle[p] = 0;
                    m_puzzle[p, old] = pubfun.Flag.normal;
                    c.m_subcells[old - 1].Visible = true;
                    if (old != cand)
                    {
                        m_puzzle[p, cand] = pubfun.Flag.normal;
                        c.m_subcells[cand - 1].Visible = true;
                    }
                }
                else
                {
                    m_puzzle[p, cand] = pubfun.Flag.normal;
                    c.m_subcells[cand - 1].Visible = true;
                }
            }
            //if(nodes.Count>0)
            if(emitEvent)
            {
                puzzle_changed(nodes);
            }
        }

        private bool hasError(ref Point p)
        {
            Debug.WriteLine(m_puzzle.exportPuzzle());
            Debug.WriteLine(m_puzzle2.exportPuzzle());
            for (int x = 1; x <= 9; ++x)
            {
                for (int y = 1; y <= 9; ++y)
                {
                    int val = m_puzzle2[x, y];
                    if(val==0)
                    {
                        Debug.Write("Why???\r\n");
                    }
                    if (m_puzzle[x, y] > 0 && m_puzzle[x, y] != val)                        
                    {
                        p = new Point(x, y);
                        return true;
                    }
                    if(m_puzzle[x, y] == 0 && m_puzzle[x, y, val] != pubfun.Flag.normal)
                    {
                        p = new Point(x, y);
                        return true;
                    }
                }
            }
            return false;
        }

        private bool undoErrorStep(bool test)
        {
            tip_clear_color_hint(false);
            Point p=new Point(0,0);
            bool ret = false;
            //如果有错，必然是从手动错误开始的，所以倒序撤销最后一次手工操作后，再次检查
            while (hasError(ref p) && m_current_op>0 && m_ops.Count>0)
            {
                if (test)//如果只是检测是否有错误步骤，则不需要做后面的处理
                    return ret;
                int undocnt = 0;
                for (int i = m_ops.Count - 1; i >= 0; --i)
                {
                    foreach (operation op in m_ops[i])
                    {
                        if (op.helper == operation.SolveHelper.Manual) //定位应该撤销到哪里
                        {
                            ret = true;
                            m_current_op = i;
                            while (m_ops.Count > m_current_op)
                            {
                                this.undoOperations(m_ops[m_ops.Count - 1]);
                                m_ops.RemoveAt(m_ops.Count - 1);
                                undocnt++;
                            }
                            break;
                        }
                    }
                    if (undocnt > 0) break;//有undo操作，重新检查错误
                }
                if (undocnt == 0 )//避免死循环（解法出错的时候会导致这个情况发生）
                {
                    MessageBox.Show("当前局面存在错误，并且检测到可能是使用到的辅助解题算法存在错误，请将解题步骤复制下来，连同初始局面一起发送给 ttylikl@qq.com");
                    break;
                }
            }
            if (ret)
            {
                updatePanel();
                undo_count++;
            }
            return ret;
        }


        //用着色方式显示提示的相关函数
        private void tip_clear_color_hint(bool dohint)//如果是提示状态，退出提示模式
        {
            //setStatusText("");
            this.tabPop.Visible = false;
            if (sta != State.SHOWHINT )
                return;

            if (hints != null)
            {
                foreach (int[] hint in hints)
                {
                    cell c = getCell(new Point(hint[1], hint[2]));
                    switch (hint[0])
                    {
                        case 0: //对数格的操作
                            c.BackColor = getBackColor(c);// c.bkcolor;//前景色不改
                            foreach (subcell sc in c.m_subcells)
                            {
                                sc.BackColor = getBackColor(sc);// sc.bkcolor;
                                //sc.ForeColor = Color.Black;
                                sc.Font = scFont;
                            }
                            break;
                        case 1://对候选数的操作
                        case 2://对候选数的操作
                            {
                                foreach (subcell sc in c.m_subcells)
                                {
                                    sc.BackColor = getBackColor(sc);// sc.bkcolor;
                                    //sc.ForeColor = Color.Black;
                                    sc.Font = scFont;
                                }
                                break;
                            }
                    }
                }
            }

            sta = State.PLAYING;//必须在确认操作前改变状态，否则会递归锁死
            hints = null;

            if (dohint&&hint_op!=null)//需要将提示的操作确认
            {
                List<operation> ops = new List<operation>();
                if (hint_op.m_op == operation.opname.set_candidate_none)
                    hint_op.m_op = operation.opname.set_candidate_tag;
                ops.Add(hint_op);
                m_ops.Add(ops);
                redoOperations(ops);
                while (true)
                {
                    if (m_ops.Count > m_current_op)
                        m_ops.RemoveAt(m_ops.Count - 1);
                    else
                        break;
                }
                m_ops.Add(ops);
                m_current_op++;
            }

            hint_op = null;
        }

        private void tip_show_color_hint()
        {
            if (sta == State.SHOWHINT && hints != null && hints.Count > 0)
            {
                foreach (int[] hint in hints)
                {
                    cell c = getCell(new Point(hint[1], hint[2]));
                    //if (c.xy == hotpoint)
                    //{
                    //    c.ml_bkcolor = c.BackColor;
                    //}
                    if (!bShowCandidates && hint[0]!=0 )
                    {
                        for(int cand=1;cand<=9;++cand)
                        {
                            if(m_puzzle[c.xy,cand]!=pubfun.Flag.none)
                            {
                                c.m_subcells[cand-1].Visible=true;
                            }
                        }
                    }
                    switch (hint[0])
                    {
                        case 0://为Point涂色
                            {
                                Color cc = get_hint_color(hint[3]);
                                c.BackColor = cc;
                                //有需要重复刷新的可能（比如热点数显示）
                                //c.UpdateBackColor();
                            }
                            break;
                        case 1: //为候选数涂色
                            {
                                Color color = get_hint_color(hint[3]);
                                c.m_subcells[hint[4] - 1].BackColor = color;
                            }
                            break;
                        case 2://删除候选数
                            {
                                Color color = get_hint_color(hint[3]);
                                c.m_subcells[hint[4] - 1].Font = new System.Drawing.Font("宋体", scFont.Size,
                                    System.Drawing.FontStyle.Strikeout | System.Drawing.FontStyle.Underline | System.Drawing.FontStyle.Bold, 
                                    System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                                c.m_subcells[hint[4] - 1].BackColor = color;
                            }
                            break;
                        default:
                            Debug.WriteLine("还不支持的提示操作[" + hint[0] + "]");
                            break;
                    }
                }
                cell hc = getCell(hotpoint);
                hc.ml_bkcolor = hc.BackColor;
                foreach (subcell sc in hc.m_subcells)
                {
                    sc.ml_bkcolor = sc.BackColor;
                }
            }
        }

        private bool isContain(List<Point> pts, Point pt)
        {
            foreach(Point p in pts)
            {
                if (p == pt)
                    return true;
            }
            return false;
        }

        public enum HintColor { Yellow = 0, YellowGreen, Red, Blue, Cyan, Green, };
        public Color get_hint_color(String strc)
        {
            foreach (Color c in Enum.GetValues(typeof(Color)))
            {
                if (c.ToString() == strc)
                    return c;
            }
            return Color.Black;
        }
        public Color get_hint_color(int v)
        {
            switch ((HintColor)v)
            {
                case HintColor.Yellow: return Color.Yellow;
                case HintColor.YellowGreen: return Color.YellowGreen;
                case HintColor.Red: return Color.Red;
                case HintColor.Blue: return Color.Blue;
                case HintColor.Cyan: return Color.Cyan;
                case HintColor.Green: return Color.Green;
                default:
                    return Color.Black;
            }
        }
        //此函数比较冗长！因为跟用户打交道，不需要太多技巧，只要能有效提示用户即可
        private void tip_get_color_hint(operation op)
        {
            //if(bShowCandidates)//非候选数方式暂时不提供此方式的提示帮助
            {
                sta = State.SHOWHINT;
                switch(op.helper)
                {
                    //BUG+1解法
                    case operation.SolveHelper.BUG1:
                        {
                            if (op.tip_points == null || op.tip_points.Count != 1)
                                break;
                            if (op.tip_number == null || op.tip_number.Count != 1)
                                break;
                            hints = new List<int[]>();
                            hints.Add(new int[] { 0, op.tip_points[0].X, op.tip_points[0].Y, (int)HintColor.YellowGreen });
                            int cand=op.tip_number[0];
                            Point p = op.tip_points[0];
                            foreach (iterator it in  new iterator[] {new iteratorX(m_puzzle.m_numbers,p), 
                                new iteratorY(m_puzzle.m_numbers, p), 
                                new iteratorZ(m_puzzle.m_numbers, p) })
                            {
                                foreach (number num in it)
                                {
                                    if(num[cand-1] == pubfun.Flag.normal)
                                    {
                                        bool bExist = false;
                                        foreach(int [] h in hints)
                                        {
                                            if(h[1]==num.xy.X && h[2]==num.xy.Y)
                                            {
                                                bExist = true;
                                                break;
                                            }
                                        }
                                        if(bExist)
                                            continue;
                                        hints.Add(new int[] { 1, num.xy.X, num.xy.Y, (int)HintColor.Yellow, cand });
                                    }
                                }
                            }
                            hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Red, cand });
                        }
                        break;
                    //唯一矩形法
                    case operation.SolveHelper.UniqueRectangle6:
                    case operation.SolveHelper.UniqueRectangle7:
                        {
                            if (op.tip_itor == null || op.tip_itor.Count !=2)
                                break;
                            if (op.tip_points == null || op.tip_points.Count !=4)
                                break;
                            if (op.tip_number == null || op.tip_number.Count != 2)
                                break;
                            hints = new List<int[]>();
                            foreach (Point p in op.tip_points)
                            {
                                hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Green });
                                foreach (int cand in m_puzzle.get_number(p).candidates())
                                {
                                    if (cand == op.values[0])
                                    {
                                        if(pubfun.find(op.m_points,p))
                                            hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, cand });
                                        else
                                            hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, cand });
                                    }
                                    else if (cand == op.tip_number[0] || cand == op.tip_number[1])
                                        hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, cand });
                                    //else
                                    //    hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Cyan, cand });
                                }
                            }
                            foreach (iterator it in op.tip_itor)
                            {
                                foreach (number num in it)
                                {
                                    if(!pubfun.find(op.tip_points,num.xy))
                                        hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.Yellow });
                                }
                            }
                        }
                        break;
                    case operation.SolveHelper.UniqueRectangle3:
                        {
                            if (op.tip_points == null || op.tip_points.Count < 5)
                                break;
                            if (op.tip_number == null || op.tip_number.Count != 2)
                                break;
                            hints = new List<int[]>();
                            for(int i=0;i<op.tip_points.Count;++i)
                            {
                                Point p = op.tip_points[i];
                                if (i < 4)
                                {
                                    hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Green });
                                    if (m_puzzle[p, op.tip_number[0]] == pubfun.Flag.normal)
                                        hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, op.tip_number[0] });
                                    if (m_puzzle[p, op.tip_number[1]] == pubfun.Flag.normal)
                                        hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, op.tip_number[1] });
                                    foreach (int cand in op.values)
                                    {
                                        if (m_puzzle[p, cand] == pubfun.Flag.normal)
                                            hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Red, cand });
                                    }
                                }
                                else
                                {
                                    hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Red });
                                }
                            }
                            foreach (Point p in op.m_points)
                            {
                                if (m_puzzle[p, op.values[0]] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, op.values[0] });
                            }
                        }
                        break;
                    case operation.SolveHelper.UniqueRectangle1:
                        {
                            if (op.tip_points == null || op.tip_points.Count != 4)
                                break;
                            if (op.tip_number == null || op.tip_number.Count != 2)
                                break;
                            hints = new List<int[]>();
                            foreach (Point p in op.tip_points)
                            {
                                hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Green });
                                if(m_puzzle[p,op.tip_number[0]]==pubfun.Flag.normal)
                                    hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, op.tip_number[0] });
                                if (m_puzzle[p, op.tip_number[1] ] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, op.tip_number[1] });
                                if (m_puzzle[p, op.values[0] ] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Red, op.values[0] });
                            }
                        }
                        break;
                    case operation.SolveHelper.UniqueRectangle4:
                        {
                            if (op.tip_points == null || op.tip_points.Count != 4)
                                break;
                            if (op.tip_number == null || op.tip_number.Count != 2)
                                break;
                            if (op.tip_itor == null || op.tip_itor.Count != 1)
                                break; 
                            hints = new List<int[]>();
                            foreach (Point p in op.tip_points)
                            {
                                hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Green });
                                if (m_puzzle[p, op.tip_number[0]] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, op.tip_number[0] });
                                if (m_puzzle[p, op.tip_number[1]] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, op.tip_number[1] });
                            }
                            foreach (Point p in op.m_points)
                            {
                                if (m_puzzle[p, op.values[0]] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, op.values[0] });
                            }
                            foreach (number num in op.tip_itor[0])
                            {
                                bool exist = false;
                                foreach (int[] ht in hints)
                                {
                                    if (ht[1] == num.xy.X && ht[2] == num.xy.Y)
                                    {
                                        exist = true;
                                        break;
                                    }
                                }
                                if (!exist)
                                {
                                    hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.YellowGreen });
                                }
                            }
                        }
                        break;
                    case operation.SolveHelper.UniqueRectangle2:
                    case operation.SolveHelper.UniqueRectangle5:
                        {
                            if (op.tip_points == null || op.tip_points.Count != 4)
                                break;
                            if (op.tip_number == null || op.tip_number.Count != 2)
                                break;
                            hints = new List<int[]>();
                            foreach (Point p in op.tip_points)
                            {
                                hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Green });
                                if (m_puzzle[p, op.tip_number[0] ] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, op.tip_number[0] });
                                if (m_puzzle[p, op.tip_number[1] ] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow, op.tip_number[1] });
                                foreach (int cand in op.values)
                                {
                                    if (m_puzzle[p, cand] == pubfun.Flag.normal)
                                        hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Red, cand });
                                }
                            }
                            foreach (Point p in op.m_points)
                            {
                                if (m_puzzle[p, op.values[0] ] == pubfun.Flag.normal)
                                    hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, op.values[0]});
                            }
                        }
                        break;
                    //涉及到强链弱链画线和数格删除
                    case operation.SolveHelper.X_Chain:
                    case operation.SolveHelper.XY_Chain:
                    case operation.SolveHelper.Forcing_Chain:
                        {
                            if (op.tip_chain == null || op.tip_chain.Count < 1)
                                break;
                            if (op.tip_chain_head == null || op.tip_chain_head.Length < 4)
                                break;
                            hints = new List<int[]>();
                            bool dump = false;
                            int head_index = 0;
                            for (int i = 0; i < op.tip_chain.Count; ++i)
                            {
                                int[] node = op.tip_chain[i];
                                if (pubfun.is_same_chain_node(op.tip_chain_head, node))
                                {
                                    dump = true;
                                    head_index = i;
                                }
                                if (!dump)
                                    continue;
                                hints.Add(new int[]{1, node[0], node[1], (int)((node[3] == 1) ? HintColor.Red : HintColor.Green), node[2]});
                            }
                            hints.Add(new int[]{1, op.m_points[0].X, op.m_points[0].Y, (int)HintColor.Cyan, op.values[0]});
                        }
                        break;
                    case operation.SolveHelper.XY_Wing:
                        {
                            if (op.tip_points == null || op.tip_points.Count != 3)
                                break;
                            hints = new List<int[]>();
                            for(int i=0;i<op.tip_points.Count;++i)
                            {
                                Point p = op.tip_points[i];
                                hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.YellowGreen });
                                foreach (int cand in m_puzzle.get_number(op.tip_points[i]).candidates())
                                {
                                    int color = (int)HintColor.Cyan;
                                    if(cand==op.values[0])
                                        color = (int)HintColor.Yellow;
                                    hints.Add(new int[] { 1, op.tip_points[i].X, op.tip_points[i].Y, color , cand });
                                }
                            }
                            foreach(Point p in op.m_points)
                            {
                                hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, op.values[0] });
                            }
                        }
                        break;
                    //8、XYZ_Wing：xyz,xz,yz节点标记红色，两两相交的group数格以黄绿色标记，有候选数删除的数格以绿色标记，被删除的候选数添加删除标记
                    case operation.SolveHelper.XYZ_Wing:
                        {
                            if (op.tip_itor == null || op.tip_itor.Count < 1)
                                break;
                            if (op.tip_points == null || op.tip_points.Count < 1)
                                break;
                            hints = new List<int[]>();
                            foreach(number num in op.tip_itor[0])
                            {
                                bool isxyz=false;
                                foreach(Point p in op.tip_points)
                                {
                                    if(p==num.xy)
                                    {
                                        isxyz=true;
                                        break;
                                    }
                                }
                                if(isxyz) continue;
                                hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.YellowGreen });
                            }
                            foreach(Point p in op.tip_points)
                            {
                                hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Red });
                                hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Yellow,op.values[0] });
                            }
                            foreach(Point p in op.m_points)
                            {
                                hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, op.values[0] });
                            }
                        }
                        break;
                    //形成Fish的house里的数格标记为黄绿色，其中包含有候选数的数格标记为红色，影响到的列/行标记为粉色，排除的候选数数格为绿色，候选数加删除标记
                    case operation.SolveHelper.X_Wing:
                    case operation.SolveHelper.SwordFish:
                    case operation.SolveHelper.JellyFish:
                        {
                            if (op.tip_number == null || op.tip_number.Count < 1)
                                break;
                            if (op.tip_points == null || op.tip_points.Count < 1)
                                break;
                            int xy = op.tip_number[0];
                            hints = new List<int[]>();
                            List<iterator> itx = new List<iterator>();
                            List<iterator> ity = new List<iterator>();
                            foreach(Point p in op.tip_points)
                            {
                                iterator ix = new iteratorX(m_puzzle.m_numbers, p);
                                iterator iy = new iteratorY(m_puzzle.m_numbers, p);
                                bool exist = false;
                                foreach(iterator it in itx)
                                {
                                    if(it.isEqual(ix))
                                    {
                                        exist = true;
                                        break;
                                    }
                                }
                                if (!exist)
                                    itx.Add(ix); 
                                exist = false;
                                foreach (iterator it in ity)
                                {
                                    if (it.isEqual(iy))
                                    {
                                        exist = true;
                                        break;
                                    }
                                }
                                if (!exist)
                                    ity.Add(iy);
                            }
                            foreach(iterator it in itx)
                            {
                                foreach(number num in it)
                                {
                                    bool iskeycell = false;
                                    foreach(Point p in op.tip_points)
                                    {
                                        if(p==num.xy)
                                        {
                                            iskeycell = true;
                                            break;
                                        }
                                    }
                                    if (!iskeycell)
                                    {
                                        hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (xy == 0) ? (int)HintColor.Yellow : (int)HintColor.YellowGreen });
                                    }
                                }
                            }
                            foreach (iterator it in ity)
                            {
                                foreach (number num in it)
                                {
                                    bool iskeycell = false;
                                    foreach (Point p in op.tip_points)
                                    {
                                        if (p == num.xy)
                                        {
                                            iskeycell = true;
                                            break;
                                        }
                                    }
                                    if (!iskeycell)
                                    {
                                        bool hasyellow = false; //如果已经填为黄色数格，不再覆盖
                                        foreach(int[] hs in hints)
                                        {
                                            if(hs[1]==num.xy.X && hs[2]==num.xy.Y)
                                            {
                                                if (hs[3] == (int)HintColor.Yellow)
                                                    hasyellow = true;
                                                break;
                                            }
                                        }
                                        if(!hasyellow)
                                            hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (xy == 0) ? (int)HintColor.YellowGreen : (int)HintColor.Yellow });
                                    }
                                }
                            }
                            foreach(Point p in op.tip_points)
                            {
                                hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Cyan });
                                hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Red,op.values[0]});
                            }
                            foreach(Point p in op.m_points)
                            {
                                hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, op.values[0] });
                            }
                        }
                        break;
                    //数集所在house标记为黄色，所在数格为黄绿色，被删除的候选数添加删除标记，对使得推导成立的数格用用色标识
                    case operation.SolveHelper.HiddenPair:
                    case operation.SolveHelper.HiddenTriple:
                    case operation.SolveHelper.HiddenQuad:
                        {
                            if (op.tip_itor == null || op.tip_itor.Count < 1)
                                break;
                            if (op.tip_number == null || op.tip_number.Count < 1)
                                break;
                            if (op.tip_points == null || op.tip_points.Count < 1)
                                break;
                            hints = new List<int[]>();
                            foreach(number num in op.tip_itor[0])
                            {
                                if (!isContain(op.tip_points,num.xy))
                                {
                                    hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.Yellow });
                                }
                                else
                                {
                                    hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.YellowGreen });
                                }
                            }
                            foreach(Point p in op.tip_points)
                            {
                                foreach(int cand in op.tip_number)
                                {
                                    if(m_puzzle[p,cand]==pubfun.Flag.normal)
                                    {
                                        hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, cand });
                                    }
                                }
                            }
                        }
                        break;
                    //数集所在方格标记红色，所在house标记绿色，被删除的候选数添加删除标记
                    case operation.SolveHelper.NakedPair:
                    case operation.SolveHelper.NakedTriple:
                    case operation.SolveHelper.NakedQuad:
                        {
                            if (op.tip_itor == null || op.tip_itor.Count < 1)
                                break;
                            hints = new List<int[]>();
                            iterator it = op.tip_itor[0];
                            foreach(number num in it)
                            {
                                bool isset=false;
                                foreach(Point p in op.tip_points)
                                {
                                    if(p==num.xy)
                                    {
                                        isset = true;
                                        break;
                                    }
                                }
                                if (isset)
                                {
                                    hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.Cyan });
                                    foreach(int cand in num.candidates())
                                    {
                                        hints.Add(new int[] { 1, num.xy.X, num.xy.Y, (int)HintColor.Yellow, cand });
                                    }
                                }
                                else
                                    hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.YellowGreen });
                            }
                            foreach(Point p in op.m_points)
                            {
                                foreach (int cand in op.values)
                                {
                                    hints.Add(new int[] { 2, p.X, p.Y, (int)HintColor.Red, cand });
                                }
                            }
                        }
                        break;
                    //标记第一个house为黄色，候选数所在的数格为红色，被排除的行列块为黄绿色，排除的候选数加删除标记
                    case operation.SolveHelper.IntersectionRemoval:
                        {
                            if (op.tip_itor == null || op.tip_itor.Count < 2)
                                break;
                            iterator itor = op.tip_itor[0];
                            iterator it = op.tip_itor[1];
                            int cand=op.values[0];
                            hints = new List<int[]>();
                            //it为包含需要删除数格的
                            foreach (number num in it) //填色表示有被排除方块的house
                            {
                                hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.YellowGreen });
                                if (num[cand - 1] == pubfun.Flag.normal)
                                {
                                    if(!itor.ContainPoint(num.xy))
                                        hints.Add(new int[] { 2, num.xy.X, num.xy.Y, (int)HintColor.Red, cand });
                                    else
                                        hints.Add(new int[] { 1, num.xy.X, num.xy.Y, (int)HintColor.Yellow, cand });
                                }
                            }
                            foreach (number num in itor)//填色表示得出推导的第一个house
                            {
                                if (it.ContainPoint(num.xy))
                                    continue;
                                hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.Yellow});
                            }
                        }
                        break;
                    //唯一数格标记绿色，在group里寻找其他几个数格，将其标记为红色，将这些数与唯一数格的交集数格标记为黄绿色
                    case operation.SolveHelper.NakedSingleNumber:
                        {
                            Point p = op.m_points[0];
                            int cand = op.values[0];
                            hints = new List<int[]>();
                            hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Yellow });
                            hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Red, cand });
                            iterator[] its = new iterator[] { new iteratorX(m_puzzle.m_numbers, p), new iteratorY(m_puzzle.m_numbers, p), new iteratorZ(m_puzzle.m_numbers, p) };
                            List<int> ns = new List<int>();
                            for (int i = 1; i <= 9; ++i)
                            {
                                ns.Add(i);
                            }
                            List<number> numlist = new List<number>();
                            foreach (iterator it in its)
                            {
                                foreach(number num in it)
                                {
                                    if (num.xy == p) continue;
                                    if (num.value == 0)
                                    {
                                        hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.YellowGreen });
                                        //Debug.WriteLine("设置" + pubfun.strNumber(num) + "为" + HintColor.YellowGreen);
                                        continue;
                                    } 
                                    bool find = false;
                                    foreach(int n in ns)
                                    {
                                        if(n==num.value)
                                        {
                                            find = true;
                                            ns.Remove(n);
                                            break;
                                        }
                                    }
                                    if (find)
                                    {
                                        hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.Red });
                                        //Debug.WriteLine("设置" + pubfun.strNumber(num) + "为" + HintColor.Red);
                                    }
                                    else
                                    {
                                        bool isset = false;
                                        foreach (int[] nl in hints)
                                        {
                                            if (nl[1] == num.xy.X && nl[2] == num.xy.Y)
                                                isset = true;
                                        }
                                        if (!isset)
                                        {
                                            hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.YellowGreen });
                                            //Debug.WriteLine("设置" + pubfun.strNumber(num) + "为" + HintColor.YellowGreen);
                                        }
                                    }
                                }
                            }
                        }
                        break;
                    //隐式唯一数法：唯一数格标记绿色，对在house里的其他未填值的数格所在的house寻找该候选数，寻找到数格标记为红色，所在house其他数格标记为黄色
                    case operation.SolveHelper.HiddenSingleNumber:                        
                        {
                            Point p = op.m_points[0];
                            int cand = op.values[0];
                            hints = new List<int[]>();
                            hints.Add(new int[] { 0, p.X, p.Y, (int)HintColor.Yellow });
                            hints.Add(new int[] { 1, p.X, p.Y, (int)HintColor.Red, cand });
                            iterator[] its = new iterator[] { new iteratorX(m_puzzle.m_numbers, p), new iteratorY(m_puzzle.m_numbers, p), new iteratorZ(m_puzzle.m_numbers, p) };
                            if (op.tip_itor == null || op.tip_itor.Count < 1) break;
                            iterator itor = op.tip_itor[0] ;
                            
                            //Debug.WriteLine("开始遍历" + pubfun.strIteratorName(itor));
                            List<iterator> itlist = new List<iterator>();
                            foreach (number num in itor)
                            {
                                if (num.xy == p)
                                    continue;
                                //同house也需要改变颜色，不然不明显
                                hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.Cyan });
                                //Debug.WriteLine("设置" + pubfun.strPoint(num.xy) + "为" + HintColor.Cyan);

                                if (num.value > 0)
                                    continue;

                                bool exist = false;
                                foreach (iterator it in itlist)
                                {
                                    if (it.ContainPoint(num.xy))
                                    {
                                        exist = true;
                                        break;
                                    }
                                }
                                if (exist) continue;

                                //hints.Add(new int[] { 0, num.xy.X, num.xy.Y, (int)HintColor.YellowGreen });
                                its = new iterator[] { new iteratorZ(m_puzzle.m_numbers, num.xy),new iteratorX(m_puzzle.m_numbers, num.xy), new iteratorY(m_puzzle.m_numbers, num.xy),  };
                                //寻找值为p的
                                foreach (iterator it in its)
                                {
                                    bool done = false;
                                    if (itor.isEqual(it))//不需要遍历house本身
                                    {
                                        //Debug.WriteLine("跳过" + pubfun.strIteratorName(it));
                                        continue;
                                    }
                                    foreach (number nn in it)
                                    {
                                        if (nn.value == cand)
                                        {
                                            //用来排除可能被包含的其他itor里的数格
                                            itlist.Add(it);
                                            //itlist.Add(new iteratorX(m_puzzle.m_numbers, nn.xy));
                                            //itlist.Add(new iteratorY(m_puzzle.m_numbers, nn.xy));
                                            //itlist.Add(new iteratorZ(m_puzzle.m_numbers, nn.xy));

                                            //为it涂色，为nn涂色
                                            hints.Add(new int[] { 0, nn.xy.X, nn.xy.Y, (int)HintColor.Red });
                                            //Debug.WriteLine("设置" + pubfun.strPoint(nn.xy) + "为" + HintColor.Red);
                                            foreach (number nc in it)
                                            {
                                                if (nc.xy == nn.xy) continue;

                                                if (itor.ContainPoint(nc.xy))
                                                {
                                                    //Debug.WriteLine(pubfun.strIteratorName(itor) + "包含了" + pubfun.strPoint(nc.xy) + "，跳过");
                                                    continue;
                                                }
                                                //Debug.WriteLine("设置" + pubfun.strPoint(nc.xy) + "为" + HintColor.YellowGreen);
                                                hints.Add(new int[] { 0, nc.xy.X, nc.xy.Y, (int)HintColor.YellowGreen });
                                            }
                                            done = true;
                                            break;
                                        }
                                    }
                                    if (done) break;
                                }
                            }
                        }
                        break;
                    default:
                        return;
                }
            }
        }
        private void getTip()
        {
            //隐藏热点数格，否则显示提示颜色后会出现热点数格被固定并且出现两个的问题
            cell c = getCell(hotpoint);
            c.BackColor = c.bkcolor;

            tip_clear_color_hint(true);//确认和清除上一次的操作
            if(m_puzzle.getPuzzleStatus()==puzzle.Status.SUCCESS)
            {
                updatePanel(); 
                GameFinished();
                return;
            }
            tip_count++;
            List<operation> ops = m_solver.getTip();
            if (ops.Count > 0)
            {
                int i = 0;
                hint_op = ops[i];
                while (i < ops.Count)
                {
                    if (ops[i].m_op == operation.opname.set_candidate_none)
                    {
                        foreach (Point p in ops[i].m_points)
                        {
                            foreach (int cand in ops[i].values)
                            {
                                if (m_puzzle[p, cand] == pubfun.Flag.normal)
                                {
                                    setStatusText(ops[i].info,0);
                                    tip_get_color_hint(ops[i]);
                                    updatePanel();
                                    return;
                                }
                            }
                        }
                    }
                    else
                    {
                        if (ops[i].helper == operation.SolveHelper.Guess)
                        {
                            MessageBox.Show("无法提供进一步的提示了，如果你有可以解决此问题的技巧，请将题目和解题技巧一并发邮件给 ttylikl@qq.com 。\r\n" + ops[i].info);
                        }
                        setStatusText(ops[i].info, 0);
                        tip_get_color_hint(ops[i]);
                        updatePanel();
                        return;
                    }
                    ++i;
                }
            }
            else
            {
                MessageBox.Show("无法再得出提示来解决题目!");
            }
        }


        private void buttonPaste_Click(object sender, EventArgs e)
        {
            pasteFromClipboard();
        }

        private void buttonAutoSolver_Click(object sender, EventArgs e)
        {
            autosolvePuzzle();
        }

        private void buttonStepSolver_Click(object sender, EventArgs e)
        {
            singleStepSolvePuzzle();
        }

        private void buutonReset_Click(object sender, EventArgs e)
        {
            resetPuzzle();
        }

        private void copySteps()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("游戏题目：\r\n");
            sb.Append(pubfun.formatPuzzleString(strCurrentSudoku, pubfun.PuzzleStringFormat.FormatTableAscii));
            sb.Append("\r\n------------\r\n");
            sb.Append(pubfun.formatPuzzleString(strCurrentSudoku, pubfun.PuzzleStringFormat.FormatLine91)); 
            sb.Append("\r\n------------\r\n");
            sb.Append(pubfun.formatPuzzleString(strCurrentSudoku, pubfun.PuzzleStringFormat.FormatMatrix9x9));
            sb.Append("\r\n------------\r\n当前局面");
            if (m_puzzle.getPuzzleStatus() == puzzle.Status.SUCCESS)
            {
                sb.Append("[完成]");
            }
            else
            {
                sb.Append("[未完成]");
                if(undoErrorStep(true))
                {
                    sb.Append("[注意：当前解题步骤存在错误！]");
                }
            }
            sb.Append("\r\n");
            String strCurrentPuzzle = m_puzzle.exportPuzzleCompact();
            sb.Append(pubfun.formatPuzzleString(strCurrentPuzzle, pubfun.PuzzleStringFormat.FormatTableAscii));
            sb.Append("\r\n\r\n解题步骤：\r\n");
            sb.Append("\r\n------------\r\n");
            foreach (List<operation> ops in m_ops)
            {
                foreach (operation op in ops)
                {
                    sb.Append(op.info);
                    sb.Append("\r\n");
                }
                sb.Append("\r\n------------\r\n");
            }
            Clipboard.SetDataObject(sb.ToString(), true);

        }

        private void buttonCopySteps_Click(object sender, EventArgs e)
        {
            copySteps();
        }


        private void buttonGenerator_Click(object sender, EventArgs e)
        {
            startNewPuzzle();
        }

        private void buttonSavePuzzle_Click(object sender, EventArgs e)
        {
            savePuzzle();
        }

        private void buttonLoadPuzzle_Click(object sender, EventArgs e)
        {
            loadPuzzle();
        }

        private void buttonAboutLink(object sender, EventArgs e)
        {
            AboutBox ab = new AboutBox();
            ab.ShowDialog();
        }
 
        private void linkGoogleCode_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://code.google.com/p/klsudoku/");  
        }

        private void buttonSingleUndo_Click(object sender, EventArgs e)
        {
            undoSingle();
        }

        private void buttonSingleRedo_Click(object sender, EventArgs e)
        {
            redoSingle();
        }

        private void buttonExit(object sender, EventArgs e)
        {
            Close();
        }


        private void buttonUndoError_Click(object sender, EventArgs e)
        {
            undo_count++;
            undoErrorStep(false);
        }


        private void buttonGetTip_Click(object sender, EventArgs e)
        {
            getTip();
        }

        private void buttonOption(object sender, EventArgs e)
        {
            Config conf=new Config();
            //conf.Location=new Point(this.Left,this.Top);
            //conf.Location=this.Location;
            conf.ShowDialog();
            //同步选项变化
            loadConfig();
            updatePanel();
        }

        private void SudokuPanel_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (this.WindowState != System.Windows.Forms.FormWindowState.Maximized)
            {
                if (this.Location.X >= 0 && this.Location.Y >= 0)
                {
                    ci["last_localtion_x"] = this.Location.X.ToString();
                    ci["last_localtion_y"] = this.Location.Y.ToString();
                }
                if(this.Size.Width>100 && this.Size.Height>100)
                {
                    ci["last_size_width"] = this.Size.Width.ToString();
                    ci["last_size_height"] = this.Size.Height.ToString();
                }
                ci["last_window_maximized"] = "0";
            }
            else
                ci["last_window_maximized"] = "1";
            Debug.WriteLine(DateTime.Now.ToString("T"));
            Debug.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
            ci.notifyExit();
            Debug.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
            Debug.WriteLine(DateTime.Now);
        }

        private void buttonInput_Click(object sender, EventArgs e)
        {
            //if(sta==State.PLAYING || sta== State.INPUTING ||sta== State.SHOWHINT)
            {
                tip_clear_color_hint(false);
                m_puzzle = new puzzle();
                m_puzzle.puzzleChanged += puzzle_changed;//注册变化事件通知
                bShowCandidates = true;
                show_all_candidates(true);
                changeStateInput();
                sta = State.INPUTING;
                updatePanel();
            }
        }
        private void changeStateInput()
        {
            this.buttonAutoSolver.Enabled = false;
            this.buttonReset.Enabled = false; ;
            this.buttonStepSolver.Enabled = false;
            this.保存游戏ToolStripMenuItem.Enabled = false;
            this.复制题目ToolStripMenuItem.Enabled = false;
            this.buttonSingleUndo.Enabled = false;
            this.解出答案ToolStripMenuItem.Enabled = false;
            this.buttonGetTip.Enabled = false;
            this.buttonSingleRedo.Enabled = false;
            this.buttonUndoError.Enabled = false;
            this.复制解题过程ToolStripMenuItem.Enabled = false;
            this.单步解题ToolStripMenuItem.Enabled = false;
            this.重新开始ToolStripMenuItem.Enabled = false;
            this.toolStripMenuItemReset.Enabled = false;
            this.toolStripMenuItemGetTip.Enabled = false;
            this.toolStripMenuItemRedoSingle.Enabled = false;
            this.toolStripMenuItemUndoSingle.Enabled = false;
            this.toolStripMenuItemUndoError.Enabled = false;
            this.toolStripButtonCopy.Enabled = false;
            this.toolStripButtonSave.Enabled = false;

            this.toolStripButtonInputOver.Enabled = true;
            toolStripMenuItemInputOver.Enabled = true;

            foreach (cellset cs in m_cellsets)
            {
                foreach (cell c in cs.m_cells)
                {
                    c.solid = false;
                    c.ForeColor = SolidNumberForeColor;
                }
            }
            nClueNumber = 0;//统计初始数
        }
        private void changeStateInputOver()
        {
            this.buttonAutoSolver.Enabled = true;
            this.buttonReset.Enabled = true; ;
            this.buttonStepSolver.Enabled = true;
            this.保存游戏ToolStripMenuItem.Enabled = true;
            this.复制题目ToolStripMenuItem.Enabled = true;
            this.buttonSingleUndo.Enabled = true;
            this.解出答案ToolStripMenuItem.Enabled = true;
            this.buttonGetTip.Enabled = true;
            this.buttonSingleRedo.Enabled = true;
            this.buttonUndoError.Enabled = true;
            this.复制解题过程ToolStripMenuItem.Enabled = true;
            this.单步解题ToolStripMenuItem.Enabled = true;
            this.重新开始ToolStripMenuItem.Enabled = true;
            this.toolStripMenuItemReset.Enabled = true;
            this.toolStripMenuItemGetTip.Enabled = true;
            this.toolStripMenuItemRedoSingle.Enabled = true;
            this.toolStripMenuItemUndoSingle.Enabled = true;
            this.toolStripMenuItemUndoError.Enabled = true;
            this.toolStripButtonCopy.Enabled = true;
            this.toolStripButtonSave.Enabled = true;
            this.toolStripButtonInput.Enabled = true;

            this.toolStripButtonInputOver.Enabled = false;
            toolStripMenuItemInputOver.Enabled = false;

        }
        private void buttonInputOver_Click(object sender, EventArgs e)
        {
            if(sta==State.INPUTING)
            {
                String str = m_puzzle.exportPuzzle();
                dlx_solver ds = new dlx_solver();
                //ds.do_solve(str);
                int scnt = ds.solution_count(str);
                if (scnt == 1)
                {
                    if (startPuzzle(str))
                        StartGetLvlThread(); //this.Text = get_lvl_str(str) + " " + this.Text;
                }
                else if (scnt > 1)
                {
                    MessageBox.Show("此局面不止一个解，请重新输入！");
                    return;
                }
                else
                {
                    MessageBox.Show("此局面无解，请重新输入！");
                    return;
                }
            }
        }

        private void toolStripMenuItemHandBook_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://code.google.com/p/klsudoku/wiki/HandBook");  
        }

        private void toolStripMenuItemDownloadHandBook_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://klsudoku.googlecode.com/files/KLSudoku%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C.doc");  
        }

        private void toolStripMenuItemSudoPedia_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.sudopedia.org/wiki/Solving_Technique");  
        }

        private void toolStripMenuItemWhatIsSudoku_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.sudopedia.org/wiki/Main_Page");  
        }

        private void toolStripMenuItemVisitProject_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://code.google.com/p/klsudoku");  
        }

        private void menuItemOperationOpening(object sender, EventArgs e)
        {
            //this.复制解题过程ToolStripMenuItem.Enabled = (m_ops.Count > 0);
            this.复制解题过程ToolStripMenuItem.Enabled = (m_current_op > 0);
        }

        private void generatorMenu_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            for (int i = 0; i < this.ToolStripMenuItemLvl.Length; ++i)
            {
                if (e.ClickedItem== ToolStripMenuItemLvl[i])
                {
                    ci["lvl"] = (i + 1).ToString();
                    this.generatorMenu.Text = "新游戏[" + e.ClickedItem.Text + "]";
                    
                    startNewPuzzle();
                    return;
                }
            }

        }

        private void buttonShowCandidates_Click(object sender, EventArgs e)
        {
            bShowCandidates=!bShowCandidates;
            ci["show_candidates"] = bShowCandidates ? "1" : "0";
            toolStripButtonShowCandidates.Checked=bShowCandidates;
        }

        private Font scFont = null;


        private void SudokuPanel_SizeChanged(object sender, EventArgs e)
        {
            Debug.WriteLine("SudokuPanel_SizeChanged");

            this.SuspendLayout();

            //定义要保留的宽高（为菜单，任务栏，左标签保留
            Point p = new Point(10, this.statusBar.Size.Height + this.menuStrip1.Size.Height+this.toolStrip1.Size.Height + 30);
            SudokuPanel panel = this;

            Size client_area=this.GetPreferredSize(Size.Empty);

            //int h = client_area.Height;
            //int w = client_area.Width;

            int h = Size.Height;
            int w = Size.Width;

            // (subcell+1)*3 -> cell
            // cell *3 +2 -> cellset
            // cellset *3 + ( p.X ,p.Y) 

            //(sc + 1) * 3 = c;
            //c * 3 + 2 = cs;
            //cs * 3 + c  = wh;
            //c*9+6+c=wh;
            //30*sc+3*10+6=wh;

            int wh = w - p.X;
            if (wh > h - p.Y)
                wh = h - p.Y;
            int sc = (wh - 36) / 30;
            int c = (sc + 1) * 3;
            int cs = c * 3 + 2;

            //重新调整起点坐标位置
            p = new Point((w - wh) / 2 + c,( h - wh)/2  + c);

            //布置面板数格
            Point pp = new Point(p.X + 1, p.Y + 1);
            float scFontSize= 2F;
            while(true)
            {
                scFont = new System.Drawing.Font("宋体", scFontSize, System.Drawing.FontStyle.Regular /*| System.Drawing.FontStyle.Bold*/, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                if (scFont.Height > sc+1)
                    break;
                scFontSize += 0.1F;
            }
            float cFontSize = 2F;
            Font cFont;
            while (true)
            {
                cFont = new System.Drawing.Font("宋体", cFontSize, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                if (cFont.Height > c+1)
                    break;
                cFontSize += 0.1F;
            }
            Point p1 = new Point(p.X+1,p.Y+1);
            for (int i = 0; i < 9; ++i)
            {
                cellset lcs = m_cellsets[i];
                Point p2 = new Point(p1.X+1,p1.Y+1);
                for (int j = 0; j < 9; ++j)
                {
                    cell lc =lcs.m_cells[j];
                    Point p3=new Point(p2.X+1,p2.Y+1);
                    for(int k=0;k<9;++k)
                    {
                        subcell lsc = lc.m_subcells[k];
                        lsc.Size = new System.Drawing.Size(sc, sc);
                        lsc.Font = scFont;
                        lsc.Location = p3;
                        p3 = new Point(p2.X + 1 + ((k + 1) % 3) * lsc.Width, p2.Y + 1 + ((k + 1) / 3) * lsc.Height);
                    }
                    lc.Size = new System.Drawing.Size(c, c);
                    lc.Font = cFont;
                    lc.Location = p2;
                    p2 = new Point(p1.X + 1 + ((j + 1) % 3) * lc.Width, p1.Y + 1 + ((j + 1) / 3) * lc.Height);
                }
                lcs.Size = new Size(cs, cs);
                lcs.Location = p1;
                p1 = new Point(p.X + 1 + ((i + 1) % 3) * lcs.Width, p.Y + 1 + ((i + 1) / 3) * lcs.Height);
            }

            //布置坐标标签
            for (int i = 0; i < 9; ++i)
            {
                Label lb = y_lable[i];
                lb.Text = (i + 1).ToString();
                lb.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
                lb.Font = new System.Drawing.Font("黑体", cFontSize, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                //lb.ForeColor = Color.DarkGray;
                Point lp = new Point(i + 1, 1);
                cell lc = getCell(lp);
                lp = lc.Location;
                lp.Y -= lc.Height;
                lb.Location = lp;
                lb.Name = lb.Text;
                lb.Size = lc.Size;
                lb.TabIndex = i + 1;
                this.Controls.Add(lb);
            }
            char ch = 'A';
            --ch;
            for (int i = 0; i < 9; ++i)
            {
                Label lb = x_lable[i];
                ++ch;
                lb.Text = ch.ToString();
                lb.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
                lb.Font = new System.Drawing.Font("黑体", cFontSize, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                lb.ForeColor = Color.DarkGray;
                Point lp = new Point(1, i + 1);
                cell lc = getCell(lp);
                lp = lc.Location;
                lp.X -= lc.Width;
                lb.Location = lp;
                lb.Name = lb.Text;
                lb.Size = lc.Size;
                lb.TabIndex = i + 1;
                this.Controls.Add(lb);
            }

            //改变弹出窗口的位置
            show_tab_pop(false);

            this.ResumeLayout();

        }

        private void label1_Click(object sender, MouseEventArgs e)
        {
            Label lb = (Label)sender;
            tabshow = 0;
            this.tabPop.Visible = false;
            if (e.Button == MouseButtons.Right)
                return;
            cell c = getCell(hotpoint);
            if (c.solid)
                return;
            int cand = 0;
            try
            {
                cand = pubfun.str2int(lb.Text);
            }
            catch (Exception)
            {
                return;
            }
            if (!pubfun.isValidValue(cand)&& cand!=0)
                return;
            if (Control.ModifierKeys == Keys.Control)
            {
                Debug.WriteLine("Ctrl+Click!");
            }
            set_candidate(hotpoint, cand,false);
            c.Text = "";
        }

        private void label2_Click(object sender,MouseEventArgs e)
        {
            Label lb = (Label)sender;
            tabshow = 1;
            this.tabPop.Visible = false;
            if (e.Button == MouseButtons.Right)
                return;
            int cand = 0;
            cell c = getCell(hotpoint);
            if (c.solid)
                return;
            try
            {
                cand = pubfun.str2int(lb.Text);
            }
            catch (Exception)
            {
                return;
            }
            if (!pubfun.isValidValue(cand) && cand!=0)
                return;
            int old = m_puzzle[hotpoint];
            if(cand!=0)
                hotnum = cand;
            m_puzzle[hotpoint] = cand;
            c.Text = "";

            List<int[]> nodes = new List<int[]>();
            nodes.Add(new int[] { 0, hotpoint.X, hotpoint.Y });
            puzzle_changed(nodes);

            if (m_puzzle.getPuzzleStatus() == puzzle.Status.SUCCESS)
            {
                GameFinished();
            }

        }

        private void tabPop_Click(object sender, EventArgs e)
        {
            this.tabPop.Visible = false;
        }

        private void label_MouseEnter(object sender, EventArgs e)
        {
            Label lb = (Label)sender;
            lb.BackColor = Color.DarkGray;
            ci.notifyWorking(false);
        }

        private void label_MouseLeave(object sender, EventArgs e)
        {
            Label lb = (Label)sender;
            lb.BackColor = DefaultBackColor;
        }

        private int notifyCount = 0;//控制触发后台任务的间隔时间
        private void timer1_Tick(object sender, EventArgs e)
        {
            String strCurrentVersion=Assembly.GetExecutingAssembly().GetName().Version.ToString();
            if (ci.hasNewVersion)
            {
                ci.hasNewVersion = false;
                DialogResult dr = MessageBox.Show(this,"KLSudoku已经有发布新版本" + ci["new_package_version"] + "（当前版本：" +
                    strCurrentVersion + "），是否下载更新？", "新版本提示！", MessageBoxButtons.YesNo);
                if (dr == DialogResult.Yes)
                {
                    System.Diagnostics.Process.Start("http://code.google.com/p/klsudoku/downloads/list");
                    String strurl = ci["new_package_url",""];
                    if (strurl != "")
                    {
                        System.Diagnostics.Process.Start(strurl);
                    }
                }
            }
            if (notifyCount > (30000 / timer1.Interval)) //30秒触发一次
            {
                ci.notifyWorking(true);
                notifyCount = 0;
            }
            else
            {
                notifyCount++;
            }
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            if (strLvlInfo.Length > 0 &&( chkLvlThread==null ||!chkLvlThread.IsAlive))
            {
                this.Text = strLvlInfo + " " + this.Text;
                strLvlInfo = "";
            }
            mybutton.Focus();//辅助主窗口可以捕捉箭头键的KeyDown事件
        }

        private List<String> strStatusText = new List<string>();

        public void setStatusText(String str,int idx)
        {
            while(strStatusText.Count<idx+1)
            {
                strStatusText.Add("");
            }
            strStatusText[idx]=str;
            statusBar.Text = strStatusText[0];
        }

        private void timerStatistics_Tick(object sender, EventArgs e)
        {
            //刷新统计情况
            int[] cnts = new int[9];//{0,0,0,0,0,0,0,0,0,};
            foreach (cellset cs in m_cellsets)
            {
                foreach (cell c in cs.m_cells)
                {
                    int n = pubfun.str2int(c.Text);
                    if (n > 0)
                    {
                        cnts[n - 1]++;
                    }
                }
            }
            StringBuilder sb = new StringBuilder();
            sb.Append("未填数情况：");
            int nTotal=0;
            for (int i = 0; i < 9; ++i)
            {
                nTotal+=cnts[i];
                //if (cnts[i] < 9)
                //{
                //    sb.Append(pubfun.int2str(i + 1));
                //    sb.Append("余");
                //    sb.Append(9 - cnts[i]);
                //    sb.Append(" | ");
                //}
                sb.Append(9 - cnts[i]);
                if ((i + 1) % 3 == 0)
                    sb.Append(" ");
            }
            if (sta != State.SHOWHINT)
            {
                setStatusText("初始数"+nClueNumber+"个，已填"+(nTotal-nClueNumber)+"未填"+(81-nTotal)+"个，"+sb.ToString(), 0);
            }


            lblMenuTimer.Text = this.staLabelTimer.Text; 
            if (hotnum > 0)
            {
                int n = (9 - cnts[hotnum - 1]);
                if (n > 0)
                    lblMenuInfo.Text = hotnum + "还余" + n + "个未填";
                else
                    lblMenuInfo.Text = hotnum + "已经全部标注填写";
            }
            else
                lblMenuInfo.Text = "";
        }

        private void timerGameWatch_Tick(object sender, EventArgs e)
        {
            dtsecs = (int)(DateTime.Now - dtstart).TotalSeconds;
            this.staLabelTimer.Text = pubfun.getSecondStr(dtsecs);

        }

        private void toolStripMenuItemCheckUpdate_Click(object sender, EventArgs e)
        {
            if (ci.chkNewVersionThread.IsAlive)
                return;
            ci.checkUpdate(true);
        }

        private void menuItemVisitTtyliklBlog_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.cnblogs.com/ttylikl");
        }

        private void toolStripMenuItemSudokuFansOrg_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.sudokufans.org.cn/");
        }

        private void toolStripMenuItemSudokuChina_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.sudokuchina.com/");
        }

        private void toolStripMenuChenCen_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://blog.sina.com.cn/chencensudoku");
        }

        private void toolStripMenuItemOUBK_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://sudoku.oubk.com/index.html");
        }

        private bool showScoreListDialog()
        {
            ScoreList scdlg = new ScoreList();
            scdlg.ShowDialog();
            if(scdlg.strSudokuReplay!="")
            {
                if (scdlg.strSudokuReplay=="New")
                {
                    //是想要开始新游戏，难度呢？
                    startNewPuzzle();
                    return true;
                }
                //有重玩的题目
                if(startPuzzle(scdlg.strSudokuReplay))
                {
                    nLvlInfo = scdlg.nLvlInfo;
                    if (nLvlInfo > 0 && nLvlInfo <= ConfigInfo.lvlList.Length)
                    {
                        this.Text = get_lvl_str(nLvlInfo) + " " + this.Text;
                    }
                }
                return true;
            }
            return false;
        }

        private void toolStripMenuItemScoreList_Click(object sender, EventArgs e)
        {
            showScoreListDialog();
        }

        private void statusBar_TextChanged(object sender, EventArgs e)
        {
            statusBar.ToolTipText = statusBar.Text;
        }

        private void SudokuPanel_MouseEnter(object sender, EventArgs e)
        {
            cell c = getCell(hotpoint);//取消热点数格颜色
            c.BackColor = getBackColor(c);
        }
    }

    public class cellset : Button
    {
        public int idx;
        public int id
        {
            get { return idx; }
            set { idx = value; }
        }
        public cell[] m_cells;
        public cellset(SudokuPanel panel, Point p, int idx)
        {
            this.idx = idx;
            this.FlatAppearance.BorderSize = 1;
            this.UseVisualStyleBackColor = true;
            this.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.Font = new System.Drawing.Font("黑体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.Location = p;
            //this.Text = idx.ToString();
            this.Name = "cellset_" + idx;
            this.Click += new System.EventHandler(this.button_Click);
            m_cells = new cell[9];

            Point pp = new Point(p.X + 1, p.Y + 1);

            for (int i = 0; i < 9; ++i)
            {
                m_cells[i] = new cell(panel, pp, i + 1);
                pp = new Point(p.X + 1 + ((i + 1) % 3) * m_cells[i].Width, p.Y + 1 + ((i + 1) / 3) * m_cells[i].Height);
            }
            this.Size = new Size(m_cells[0].Width * 3 + 2, m_cells[0].Height * 3 + 2);

            Color co = (idx % 2 == 0)?Color.LightGray:Color.White;
            
            foreach (cell c in m_cells)
            {
                foreach (subcell sc in c.m_subcells)
                {
                    sc.BackColor = co;
                    sc.bkcolor = co;
                    sc.ml_bkcolor = co;
                }
                c.BackColor = co;
                c.bkcolor = co;
                c.ml_bkcolor = co;
            }

            panel.Controls.Add(this);

        }
        private void button_Click(object sender, EventArgs e)
        {
            Debug.WriteLine("click cellset:" + idx + "!");
        }

    }

    public class cell : Label
    {
        private SudokuPanel panel;
        ConfigInfo ci = ConfigInfo.Instance();
        public subcell[] m_subcells;
        public Color bkcolor;
        public Color ml_bkcolor;
        private int idx;

        public bool solid = false;

        private Point pos;
        public Point xy
        {
            get { return pos; }
            set
            {
                pos = value;
                foreach (subcell sc in m_subcells)
                {
                    sc.xy = value;
                }
            }
        }
        public cell(SudokuPanel panel, Point p, int idx)
        {
            this.idx = idx;
            this.panel = panel;

            //this.FlatAppearance.BorderSize = 1;
            //this.FlatAppearance.BorderColor = Color.Black;
            //this.UseVisualStyleBackColor = true;
            this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;

            this.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.Font = new System.Drawing.Font("黑体", 24F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.Location = p;
            this.Name = "cell_" + idx;

            //this.Click += new System.EventHandler(this.button_Click);
            this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.button_Click);
            this.MouseEnter += new EventHandler(cell_MouseEnter);
            this.BackColorChanged += new EventHandler(cell_BackColorChanged);
            this.TextChanged += new EventHandler(cell_TextChanged);
            this.VisibleChanged += new EventHandler(cell_TextChanged);
            m_subcells = new subcell[9];
            Point pp = new Point(p.X + 1, p.Y + 1);
            for (int i = 0; i < 9; ++i)
            {
                m_subcells[i] = new subcell(panel, pp, i + 1);
                pp = new Point(p.X + 1 + ((i + 1) % 3) * m_subcells[i].Width, p.Y + 1 + ((i + 1) / 3) * m_subcells[i].Height);
            }
            this.Size = new Size(m_subcells[0].Width * 3 + 3, m_subcells[0].Height * 3 + 3);

            panel.Controls.Add(this);
            //this.ForeColor = SudokuPanel.NumberForeColor;
        }

        void cell_TextChanged(object sender, EventArgs e)
        {
            if (Visible)
            {
                if (Text == "")
                {
                    bool hotoff = (pubfun.str2int(ci["show_hot_number","1"]) == 0);
                    foreach (subcell sc in m_subcells)
                    {
                        if (sc.Visible)
                            sc.ForeColor = (!hotoff && sc.Text == panel.hotnum.ToString()) ?  panel.HotNumberForeColor : panel.SolidNumberForeColor;
                    }

                }
                else
                {
                    this.ForeColor = panel.getForeColor(this);
                }
            }
        }
        public void UpdateBackColor()
        {
            foreach (subcell sc in m_subcells)
            {
                if (sc.id == panel.hotnum)
                {
                    if (panel.m_puzzle[xy, sc.id] == pubfun.Flag.tag)
                    {
                        sc.BackColor = this.BackColor;
                        sc.ForeColor = this.BackColor;
                    }
                    else
                        sc.BackColor = panel.getBackColor(sc);
                }
                else
                    sc.BackColor = this.BackColor;
            }
        }

        void cell_BackColorChanged(object sender, EventArgs e)
        {
            UpdateBackColor();
        }

        void cell_MouseEnter(object sender, EventArgs e)
        {
            if (ci.bHotspotWithMouse)
            {
                panel.hotpoint = xy;
            }
            ci.notifyWorking(false);
        }
        private void button_Click(object sender, MouseEventArgs e)
        {
            Debug.WriteLine("click cell:" + idx + "!");
            if(solid)
                return;
            if (e.Button == MouseButtons.Right)
            {
                panel.doRClickCell(this);
                return;
            }
            panel.doClickCell(this);
        }
    }

    public class subcell : Label
    {
        public Color bkcolor;
        public Color ml_bkcolor;
        private Color m_ml_bkcolor;
        private int idx;
        ConfigInfo ci = ConfigInfo.Instance();
        public int id
        {
            get { return idx; }
        }
        private Point pos;
        public Point xy
        {
            get { return pos; }
            set { pos = value; }
        }
        private SudokuPanel panel;
        public subcell(SudokuPanel panel, Point p, int idx)
        {
            this.panel = panel;
            this.idx = idx;
            this.Size = new System.Drawing.Size(20,20);
            bkcolor = this.BackColor;
            ml_bkcolor = this.BackColor;
            m_ml_bkcolor = this.BackColor;

            this.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;

            this.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.Font = new System.Drawing.Font("宋体", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.Location = p;
            this.Name = "subcell_" + p.X + "_" + p.Y;
            this.TabIndex = 0;
            this.Text = idx.ToString();
            this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.button_MouseClick);
            this.MouseEnter += new EventHandler(subcell_MouseEnter);
            this.MouseLeave += new EventHandler(subcell_MouseLeave);
            this.VisibleChanged += new EventHandler(subcell_VisibleChanged);
            panel.Controls.Add(this);
            //this.ForeColor = SudokuPanel.NumberForeColor;
        }


        void subcell_VisibleChanged(object sender, EventArgs e)
        {
            if(Visible)
            {
                this.ForeColor = (pubfun.str2int(ci["show_hot_number","1"]) > 0) ? panel.HotNumberForeColor : panel.SolidNumberForeColor;
            }
        }

        void subcell_MouseLeave(object sender, EventArgs e)
        {
            if (ci.bHotspotWithMouse && panel.hotpoint != this.xy)
                return;
            this.BackColor = m_ml_bkcolor;
        }

        void subcell_MouseEnter(object sender, EventArgs e)
        {
            if (ci.bHotspotWithMouse)
            {
                panel.hotpoint = this.xy;
            }
            m_ml_bkcolor = this.BackColor;
            this.BackColor = Color.DarkGray;
            ci.notifyWorking(false);
        }

        private void button_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                panel.doRClickSubCell(this);
            }
            if (e.Button == MouseButtons.Left)
            {
                Debug.WriteLine("click number:" + idx + "!");
                panel.doClickSubCell(this);
            }
        }

    }
    
    //为截获方向键而放置的按钮
    public class MyButton : System.Windows.Forms.Button
    {
        protected override bool IsInputKey(System.Windows.Forms.Keys keyData)
        {
            if (keyData == System.Windows.Forms.Keys.Left
                || keyData == System.Windows.Forms.Keys.Right
                || keyData == System.Windows.Forms.Keys.Up
                || keyData == System.Windows.Forms.Keys.Down
                )
                return true;
            return base.IsInputKey(keyData);
        }
    }
}
